Merge few lists into dictionary - ios

I have 3 lists:
a = ["John", "Archie", "Levi"]
b = ["13", "20"]
c = ["m", "m", "m", "m"]
I want to merge this into one list with dictionaries:
result = [
{"name": "John", "age": "13", "gender": "m"},
{"name": "Archie", "age": "20", "gender": "m"},
{"name": "Levi", "age": "", "gender": "m"},
{"name": "", "age": "", "gender": "m"},
]

Ok, this is pretty normal computer science problem. Here is an outline of how to go about solving it:
First, identify the inputs and the desired outputs. You've done that.
Note any edge cases you need to handle
Next, map out the logic flow using pseudo-code.
Convert from pseudo-code to real code.
Test and debug.
For step 2, your data suggests that you want to handle cases where you have different numbers of elements in each source array. it looks like you want to create a dictionary for all the 0 elements in each array, then a dictionary for the 1 elements, etc. When you run out of elements for a given array, it looks like you want to skip that key in your resulting dictionary entry.
Now to pseudo-code:
Find the array with the maximum number of elements. Make this your output_count (the number of items in your output array.)
Create an output array large enough for output_count entries.
Loop from 0 to output_count - 1.
create a dictionary variable
for each input array, if there are enough elements, add a key/value pair
for that array's key and the value at the current index. Otherwise skip
that key.
add the new dictionary to the end of your output array.
That should be enough to get you started. Now see if you can convert that pseudo-code to actual code, test it, and debug it. Report back here with your actual code, and feel free to ask for help if you get stuck getting your code working.

Try like this:
let a = ["John", "Archie", "Levi"]
let b = ["13", "20"]
let c = ["m", "m", "m", "m"]
var dicArray:[[String:String]] = []
for index in 0..<max(a.count,b.count,c.count) {
dicArray.append([:])
dicArray[index]["name"] = index < a.count ? a[index] : ""
dicArray[index]["age"] = index < b.count ? b[index] : ""
dicArray[index]["gender"] = index < c.count ? c[index] : ""
}
dicArray // [["gender": "m", "age": "13", "name": "John"], ["gender": "m", "age": "20", "name": "Archie"], ["gender": "m", "age": "", "name": "Levi"], ["gender": "m", "age": "", "name": ""]]

Here is my take. I first create the array, and then use enumerate() and forEach to process each array and add them to the array of dictionaries:
let a = ["John", "Archie", "Levi"]
let b = ["13", "20"]
let c = ["m", "m", "m", "m"]
let count = max(a.count, b.count, c.count)
var result = Array(count: count, repeatedValue: ["name":"", "age":"", "gender":""])
a.enumerate().forEach { idx, val in result[idx]["name"] = val }
b.enumerate().forEach { idx, val in result[idx]["age"] = val }
c.enumerate().forEach { idx, val in result[idx]["gender"] = val }
print(result)
[["gender": "m", "age": "13", "name": "John"], ["gender": "m", "age":
"20", "name": "Archie"], ["gender": "m", "age": "", "name": "Levi"],
["gender": "m", "age": "", "name": ""]]

This should do the job
let maxLength = max(a.count, b.count, c.count)
let paddedA = a + [String](count: maxLength-a.count, repeatedValue: "")
let paddedB = b + [String](count: maxLength-b.count, repeatedValue: "")
let paddedC = c + [String](count: maxLength-c.count, repeatedValue: "")
let res = zip(paddedA, zip(paddedB, paddedC)).map {
["name": $0.0, "age": $0.1.0, "gender": $0.1.1]
}
Output
[["gender": "m", "age": "13", "name": "John"], ["gender": "m", "age": "20", "name": "Archie"], ["gender": "m", "age": "", "name": "Levi"], ["gender": "m", "age": "", "name": ""]]

Related

swift - if statement and array

I want to match a string from the DicX to a an existing title (title of a table which changes according to the cell selection).
var DicX = ["xx",
"yy",
"zz",
"qq"]
let DicYY = [["11", "22", "33", "44"],
["1", "2", "3", "4"],
["m", "n", "k", "b"],
["bb", "kk", "mm", "nn"]]
the title I'm comparing with is like this:
title = detailX.insideTitle
so I want that when the title string equal to one of the DicX strings, to show the corresponding strings for it in DicYY each one of the 4 on a button.
but can't get the match correct, I tried to do like:
var currentX = detailX.insideTitle
if DicX == currentX["DicX"] {
}
I get this message :
Cannot subscript a value of type 'String' with an index of type 'String'
how can I do the if statement? and how to get the corresponding from DicYY?
This will do the job (if i got it right).
import Foundation
let DicX = ["xx",
"yy",
"zz",
"qq"]
let DicYY = [["11", "22", "33", "44"],
["1", "2", "3", "4"],
["m", "n", "k", "b"],
["bb", "kk", "mm", "nn"]]
let searchterm = "yy"
for (index, elem) in DicX.enumerated()
{
if (searchterm != elem) { continue }
print(DicYY[index]) // This will print ["1","2","3","4"]
}

How to get value ForRowAt indexPath in tableview? [duplicate]

I want to match a string from the DicX to a an existing title (title of a table which changes according to the cell selection).
var DicX = ["xx",
"yy",
"zz",
"qq"]
let DicYY = [["11", "22", "33", "44"],
["1", "2", "3", "4"],
["m", "n", "k", "b"],
["bb", "kk", "mm", "nn"]]
the title I'm comparing with is like this:
title = detailX.insideTitle
so I want that when the title string equal to one of the DicX strings, to show the corresponding strings for it in DicYY each one of the 4 on a button.
but can't get the match correct, I tried to do like:
var currentX = detailX.insideTitle
if DicX == currentX["DicX"] {
}
I get this message :
Cannot subscript a value of type 'String' with an index of type 'String'
how can I do the if statement? and how to get the corresponding from DicYY?
This will do the job (if i got it right).
import Foundation
let DicX = ["xx",
"yy",
"zz",
"qq"]
let DicYY = [["11", "22", "33", "44"],
["1", "2", "3", "4"],
["m", "n", "k", "b"],
["bb", "kk", "mm", "nn"]]
let searchterm = "yy"
for (index, elem) in DicX.enumerated()
{
if (searchterm != elem) { continue }
print(DicYY[index]) // This will print ["1","2","3","4"]
}

Adding to dictionary dynamically

I 'm having an array of dictionary like so...
[
{
"id" : "3",
"sellingPrice" : "520",
"quantity" : "15"
},
{
"id" : "5",
"sellingPrice" : "499",
"quantity" : "-1"
},
{
"id" : "8",
"sellingPrice" : "500",
"quantity" : "79"
}
]
Now I want to add to the dictionary another key called remaining_balance with a value of 420,499 & 500 respectively. How can I achieve this..? Hope somebody can help...
It seems like you want to add a value to your dictionary that is an array:
var arrDict = Array<Dictionary<String,Any>>() //Your array
arrDict.append(["id":"3","sellingPrice":"520","quantity":"13"])
arrDict.append(["id":"5","sellingPrice":"43","quantity":"32"])
arrDict.append(["id":"8","sellingPrice":"43","quantity":"33"])
let arrValue = ["420","499","500"] //Your remaining value in array
print("Before ",arrDict)
for (index,dict) in arrDict.enumerated() {
var dictCopy = dict //assign to var variable
dictCopy["remaining_balance"] = arrValue[index]
arrDict[index] = dictCopy //Replace at index with new dictionary
}
print("After ",arrDict)
EDIT
If you are able keep an index of an array it would be possible,
Assuming that you have the index of an array
var dictCopy = arrDict[index]
dictCopy["remaining_balance"] = "666" //Your calculated value
arrDict[index] = dictCopy //Replace at index with new dictionary
var newKV = [["remaining_balance": "420"],["remaining_balance": "490"],["remaining_balance": "500"]]
let array = [["id":"3", "sellingPrice":"520", "quantity":"15"], ["id":"5", "sellingPrice":"520", "quantity":"15"], ["id":"8", "sellingPrice":"520", "quantity":"15"]]
let newArray = array.enumerated().map { (index : Int, value: [String: String]) -> [String: String] in
var dic = value
dic.merge(newKV[index]) { (_, new) -> String in
new
}
return dic
}
You could achieve it by mapping your array:
var myArray = [["id": "3", "sellingPrice": "520", "quantity" : "15"], ["id": "5", "sellingPrice": "499", "quantity" : "-1"], ["id": "8", "sellingPrice": "500", "quantity" : "79"]]
print(myArray)
/*
[["id": "3", "sellingPrice": "520", "quantity": "15"],
["id": "5", "sellingPrice": "499", "quantity": "-1"],
["id": "8", "sellingPrice": "500", "quantity": "79"]]
*/
print("___________________")
var remainingBalanceDesriedValue = 420
myArray = myArray.map { (dict: [String: String]) -> [String: String] in
var copyDict = dict
copyDict["remaining_balance"] = "\(remainingBalanceDesriedValue)"
remainingBalanceDesriedValue = (remainingBalanceDesriedValue == 420) ? 499 : (remainingBalanceDesriedValue == 499) ? 500 : 420
return copyDict
}
print(myArray)
/*
[["sellingPrice": "520", "quantity": "15", "id": "3", "remaining_balance": "420"],
["sellingPrice": "499", "quantity": "-1", "id": "5", "remaining_balance": "499"],
["sellingPrice": "500", "quantity": "79", "id": "8", "remaining_balance": "500"]]
*/
Let's assume you have an array of dictionaries like so:
var arrayOfDictionaries = [
[
"id": 3,
"sellingPrice": 520,
"quantity": 15
]
]
It is important that arrayOfDictionaries is not a let constant, otherwise it is considered immutable and you can not call append on it.
Now you init a new dictionary like:
let newDictionary = [
"id": 10,
"remaining_balance": 420,
"quantity": 15
]
Now add the newDictionary like
arrayOfDictionaries.append(newDictionary)
If the order is important
If the order is important there are a couple of ways to go about that.
When calling append the new value (in this case the new dictionary) will always be inserted at the bottom of the array.
If for some reason you can not call append in the correct order you could use insert, which inserts your dictionary at a specific position.
Yet another way is to append the values wildly and after you are done, call sort on the array.
Improvement Tips
Notice that for the values I did not use strings, as you only have numbers like "id" : 30.
Also, if you want the second key to be called remaining_balance you should call the first key selling_price instead of sellingPrice. Because of conistency.
Alternative approach
As far as I have understood you are trying to implement some software that is responsibly for selling some products.
I think you are tackling this problem from a completely wrong side.
I think you should read about database relationships. Selling products actually is a very common problem.
Maybe this will help you. I would offer a possible solution myself, but I think this misses the point of your question.
If you decide to use the database approach, you won't necessarily have to use a database. You can take the approach and implement it using simple structs/classes/arrays.
I noticed this question lacks an extension answer, yes.. I'm gonna be that guy, so here it is. This could be made more generic by supporting other types of dictionaries, feel free to pitch in ;)
Inspiration from #eason's answer.
var newKV = [["remaining_balance": "420"],["remaining_balance": "490"],["remaining_balance": "500"]]
var array = [["id":"3", "sellingPrice":"520", "quantity":"15"], ["id":"5", "sellingPrice":"520", "quantity":"15"], ["id":"8", "sellingPrice":"520", "quantity":"15"]]
extension Array where Element == [String: String] {
enum UniquingKeysStrategy {
case old
case new
}
mutating func merge(with target: Array<Element>, uniquingKeysWith: UniquingKeysStrategy = .new) {
self = self.merged(with: target)
}
func merged(with target: Array<Element>, uniquingKeysWith strategy: UniquingKeysStrategy = .new) -> Array<Element> {
let base = self.count > target.count ? self : target
let data = self.count > target.count ? target : self
return data.enumerated().reduce(into: base, {
result, data in
result[data.offset]
.merge(data.element, uniquingKeysWith: {
old, new in
if strategy == .new { return new }
return old
})
})
}
}
let mergedArrays = newKV.merged(with: array, uniquingKeysWith: .old)
array.merge(with: newKV)
Happy Coding :)

How to get proper string array in swift?

["[\"1\", \"7\", \"13\", \"19\", \"25\"]", "[\"6\", \"12\", \"13\"]"]
I am getting this as output how to get string array like this in Swift
["1", "7", "13", "19", "25", "6", "12", "13"]
I tried all to convert this array in proper array but no luck. Is there a solution for this ?
Thank You!!
Simple solution (without significant error handling), the strings can be treated as JSON
let array = ["[\"1\", \"7\", \"13\", \"19\", \"25\"]", "[\"6\", \"12\", \"13\"]"]
var result = [String]()
for item in array {
let jsonArray = try! JSONSerialization.jsonObject(with: item.data(using: .utf8)!) as! [String]
result.append(contentsOf: jsonArray)
}
print(result)
First, assuming you had a simple array of arrays, you can flatten it with flatMap:
let input = [["1", "7", "13", "19", "25"], ["6", "12", "13"]]
let output = input.flatMap { $0 }
That outputs
["1", "7", "13", "19", "25", "6", "12", "13"]
Or, even easier, just append the second array to the first one, bypassing the array of arrays altogether:
let array1 = ["1", "7", "13", "19", "25"]
let array2 = ["6", "12", "13"]
let output = array1 + array2
But your example looks like it's not an array of arrays, but rather array of descriptions of arrays, e.g. something like:
let array1 = ["1", "7", "13", "19", "25"]
let array2 = ["6", "12", "13"]
let input = ["\(array1)", "\(array2)"]
let output = ... // this is so complicated, I wouldn't bother trying it
Rather than figuring out how to reverse this array of interpolated strings, I'd suggest you revisit how you built that, bypassing interpolated strings (or description of the arrays).

How to delete group data in Swift?

I have Dictionary and I am adding to tableView.
let myArray = [["name": "First element", "foo": "bar","GroupID":"1"], ["name": "First element", "foo": "bar","GroupID":"1"],["name": "Second element", "foo": "bar","GroupID":"2"], ["name": "Second element", "foo": "bar","GroupID":"2"]]
In this dictionary I have key GroupID.
Is it possible that I can get dictionary data whose GroupID = %#?
I want to filter data based on grouping
Suppose I have four data, and group id is same in two data. I want to delete all data whose GroupID is same from dictionary.
If groupid == 1 than data will be deleted from dictionary whose GroupID == 1 and tableview will reload data.
I am doing this because I want to delete group data.
You can use filter on your Array to remove those dictionaries from your array, check this example
var subitems: [[String:String]] = [
["groupid": "1", "b": "2"],
["groupid": "3", "b": "4"],
["groupid": "1", "b": "6"]
]
var filteredSubitems = subitems.filter{
$0["groupid"] != "1" // change with your groupid
}
print(filteredSubitems)
Here is a simple way to do it:
var index = 0
for element in myArray {
if element["GroupID"] == "1" {
myArray.remove(at: 0)
index += 1
} else {
index += 1
}
}
print(myArray):
It prints out:
[["name": "Second element", "GroupID": "2", "foo": "bar"], ["name":
"Second element", "GroupID": "2", "foo": "bar"]]
Good luck!

Resources