Swift array map with comma before append new value - ios

i have this following data structure in my Realm object
var tags = List<Tag>()
"tags": [
{
"tagId": "80069",
"tagName": "A"
},
{
"tagId": "80070",
"tagName": "B"
},
{
"tagId": "80071",
"tagName": "C"
},
{
"tagId": "80073",
"tagName": "D"
}
]
So what i want to achieve is, I map all my tag name into my new array
this is my code
let realmObject = self.realm.objects(MyDTO.self)
let array = Array(realmOutletList).map{Array($0.tags).map{$0.tagName!}.joined(separator: ",")}
it prints out this
["A,B,C", "A,C,D", "B,C,D"]
What I want to achieve is like
["A","B","C", "A","C","D", "B","C","D"]
I need that kind of array because I am going to create a Set from the array and then compare with another array
The compared array will be like
["A","B","C", "A","C","D", "B","C","D"]
because of the compared Array and the realmObject Array is different, it always shows false when i use
let subset = filterSet.isSubset(of: mySet)
Can anyone guide me please??
Thanks

Let's walk through solving the issue:
Consider that you have:
let originalArray = ["A,B,C", "A,C,D", "B,C,D"]
First, we need to separate each string in originalArray by "," character, so we could do:
let modifiedArray = originalArray.map { $0.components(separatedBy: ",") }
We map it to transform each string to a strings array (separation).
So far, the output of modifiedArray would be:
[["A", "B", "C"], ["A", "C", "D"], ["B", "C", "D"]]
which is an array of strings array.
Second, we need to spilt each -string- array in modifiedArray (having one reduced strings array instead), so we could do:
var final = [String]()
for array in modifiedArray {
for string in array {
final.append(string)
}
}
OR by using reduce
let finalArray = modifiedArray.reduce([], +)
Therefore, finalArray would be:
["A", "B", "C", "A", "C", "D", "B", "C", "D"]
which is the desired result.
Conclusion
For a fully one-lined answer (following the high-order functions approach):
let originalArray = ["A,B,C", "A,C,D", "B,C,D"]
let desiredArray = originalArray.map { $0.components(separatedBy: ",") }.reduce([], +)
print(desiredArray) // ["A", "B", "C", "A", "C", "D", "B", "C", "D"]

Well, it's quite easy:
This
let array = Array(realmOutletList).map{Array($0.tags).map{$0.tagName!}.joined(separator: ",")}
should be this
let array = Array(realmOutletList).flatMap{Array($0.tags).map{$0.tagName!}}
That's all. And you will get your ["A","B","C", "A","C","D", "B","C","D"].

Related

How to sort a CSV string based on the inner values?

I have this CSV String
"B,C,D,A,E\n18945,12091,14058,2907,15132\n25,122,134,428,211"
which I have separated by \n and , and got below array:
I have this array:
[["B", "C", "D", "A", "E"], ["18945", "12091", "14058", "2907", "15132"], ["25", "122", "134", "428", "211"]]
where first array inside the main array is indicating the column names, which I need to sort alphabetically based on that the remaining arrays should also sorted.
Consider a table like this:
B -> 18945 -> 25
After sort, I am expecting an output like this:
[["A", "B", "C", "D", "E"], ["2907", "18945", "12091", "14058", "15132"], ["428", "25", "122", "134", "211"]]
IMO you should try to structure your data but if you really want to go through this path you just need to sort the first collection indices and map the collections using the sorted indices. Of course this assumes all collections have the same number of elements and the collection is not empty:
let table = [["B", "C", "D", "A", "E"], ["18945", "12091", "14058", "2907", "15132"], ["25", "122", "134", "428", "211"]]
let indices = table[0].indices.sorted { table[0][$0] < table[0][$1] }
let sorted = table.map { collection in
indices.map { collection[$0] }
}
If you want to be extra paranoid and make sure your code will never crash you can get the first collection using if let and use compact map checking if the collection contains each index before accessing them using subscript:
let table = [["B", "C", "D", "A", "E"], ["18945", "12091", "14058", "2907", "15132"], ["25", "122", "134", "428", "211"]]
if let columns = table.first {
let indices = columns.indices.sorted { columns[$0] < columns[$1] }
let sorted = table.map { collection in
indices.compactMap { collection.indices ~= $0 ? collection[$0] : nil }
}
print(sorted)
}
edit/update:
For a case insensitive sort:
let indices = columns.indices.sorted { columns[$0].caseInsensitiveCompare(columns[$1]) == .orderedAscending }
For a case and diacritic insensitive sort:
let indices = columns.indices.sorted { columns[$0].localizedStandardCompare(columns[$1]) == .orderedAscending }
This will print
[["A", "B", "C", "D", "E"], ["2907", "18945", "12091", "14058", "15132"], ["428", "25", "122", "134", "211"]]

Swift: Merge Array of dictionaries with duplicate key but unique values

I have a array of dictionaries which contains same key but different values. I want to merge these dictionaries and add all the values of same keys just like below:
var arrayofDict = [["2019":"A"],["2019":"B"],["2019":"C"],["2018":"A"],["2018":"c"],["2017":"A"],["2017":"B"],["2017":"C"],["2016":"A"],["2015":"A"],["2015":"B"]]
expected result as an Array like:
var newDict = [["2019":["A","B","C"]],["2018":["A","C"]],["2017":["A","B","C"]],["2016":["A"]],["2015":["A","B"]]]
This shows how to build a single dictionary. Your "expected result" is an array. Is this what you really expected or did you want an array?
You can iterate the dictionary items and build up the dictionary entries:
var arrayofDict = [["2019":"A"],["2019":"B"],["2019":"C"],["2018":"A"],["2018":"c"],["2017":"A"],["2017":"B"],["2017":"C"],["2016":"A"],["2015":"A"],["2015":"B"]]
var result = [String : [String]]()
for dict in arrayofDict {
for (key, value) in dict {
result[key, default: []].append(value)
}
}
print(result)
["2016": ["A"], "2018": ["A", "c"], "2015": ["A", "B"], "2019": ["A", "B", "C"], "2017": ["A", "B", "C"]]
Or, if you want an array:
let result2 = result.map { [$0.key: $0.value] }
print(result2)
[["2015": ["A", "B"]], ["2016": ["A"]], ["2019": ["A", "B", "C"]], ["2018": ["A", "c"]], ["2017": ["A", "B", "C"]]]
as #vacawama in more functional way
let result = arrayofDict.reduce(into: [String:[String]]()) { (acc, d) in
for key in d.keys {
// don't worry to force unwrap d[key], if key exist, the value is not nil
acc[key, default: []].append(d[key]!)
}
}

Combining 2 Array into dictionary [duplicate]

This question already has answers here:
Swift equivalent to `[NSDictionary initWithObjects: forKeys:]`
(5 answers)
Closed 3 years ago.
I want to combine 2 array.
arr1 = ["a", "b", "c"]
arr2 = ["1", "2", "3"]
i want to make it to be :
"a" = "1"
"b" = "2"
"c" = "3"
so if i call value "1" into label1, it means value "a" is also called into label2 just like dictionary or index.
Just like that:
let arr1 = ["a", "b", "c"]
let arr2 = ["1", "2", "3"]
let dictionary = Dictionary(uniqueKeysWithValues: zip(arr1, arr2))
It's one line code
let dict = zip(["a", "b", "c"], ["1", "2", "3"]).compactMap{[$0.0:$0.1]}.reduce([:]) { $0.merging($1) { (current, _) in current } }
print(dict)
["a": "1", "b": "2", "c": "3"]
I suggests you to use user28434's answer which is more effective than mine. I am keeping my answer as alternative second best solution

How to add element at Last index Swift

I am getting an Array from server and I store it in NSMutableArray. Now the issue is that the Array is not sorted. For eg. array = ["A","B","None","C","D"]. I want to sort it and place the "None" element at last. i.e ["A","B","C","D","None"]. Tried swapping but was unable to match the condition, as the array may increase in future. Check my code below which is not working as expected.
if array.containsObject( "None" ){
print("\(array.indexOfObject("None"))")
let noneIndex = array.indexOfObject("None")
print(noneIndex)
array.removeObject(noneIndex)
print("Remove Array:-\(array)")
array.insertObject(noneIndex, atIndex: (array.lastObject?.index)!)
print("Sorted Array:-\(array)")
}
Maybe I'm misunderstanding what it is that you need to do, but you could use sorted() on your array if you just want to sort it alphabetically.
You could also use filter to remove "None" from your array, sort it, and then append "None" as the last element
For instance, if you have
let elements = ["Alpha", "Bold", "None", "charlie", "Delta", "echo", "zebra", "k"]
You could start out by filtering it:
let filteredElements = elements.filter { $0.uppercased() != "NONE"}
Sort the filtered elements:
var sortedElements = filteredElements.sorted { $0.uppercased() < $1.uppercased()}
Append "None"
sortedElements.append("None") // ["Alpha", "Bold", "charlie", "Delta", "echo", "k", "zebra", "None"]
And be done.
Here it is combined:
let lastElement = "None"
let elements = ["Alpha", "Bold", "None", "charlie", "Delta", "echo", "zebra", "k"]
var sortedElements = elements.filter({$0.uppercased() != lastElement.uppercased()}).sorted(by: {$0.uppercased() < $1.uppercased()})
sortedElements.append(lastElement)
Hope that helps you.
var array = ["A", "B", "None", "C", "D"]
if let noneIndex = array.index(of: "None") {
array.remove(at: noneIndex)
array.append("None")
}
print(array)
This should move None at the end of the array, and sort the other elements:
let ["A", "B", "None", "C", "D"]
array.sorted { $1 == "None" || $0 < $1 } // ["A", "B", "C", "D", "None"]
This simply takes benefits of the by argument that can be passed to the sort/sorted method from Array.
Edit #MartinR had a very strong point regarding the comparison predicate from this answer, which indeed doesn't offer a strong weak ordering. Sorting the array with a correct predicate would be along the lines of:
array.sorted { $0 == "None" ? false : $1 == "None" ? true : $0 < $1 }
This will work:
// starting test array
let array = ["B", "None", "C","P","None","A", "Q"]
var sorted = array.sorted { (str1, str2) -> Bool in
return str1 < str2
}
sorted.forEach { str in
if str == "None" {
if let idx = sorted.index(of: str) {
sorted.remove(at: idx)
sorted.append(str)
}
}
}
// Sorted array is now ["A", "B", "C", "P", "Q", "None", "None"]

How to sort MultipleSelectorRow values in Eureka library in Swift?

My use case describes the necessity of a field in which the user can select multiple phases that goes from A to F. To achieve that I used the MultipleSelectorRow n Eureka library:
<<< MultipleSelectorRow<String>("phase") {
$0.title = "Phase"
$0.options = ["A", "B", "C", "D", "E", "F"]
}
When the user selects any of the options I want the value to display the selected options in alphabetical order "A,B,C...", what happens is that the text is always displayed in a random order, I've tried to achieve the alphabetical order by extending the code:
<<< MultipleSelectorRow<String>("phase") {
$0.title = "Phase"
$0.options = ["A", "B", "C", "D", "E", "F"]
}.onChange { row in
row.value = Set(row.value!.sort())
}
The expression is evaluated correctly, but I still can't get the values sorted in the alphabetical order.
While posting the question I realize that as Eureka uses a Set to store the fields it will never be sorted.
In this case I've changed the cellUpdate method to update the detailTextLabel with the sorted values as stated bellow:
<<< MultipleSelectorRow<String>("phase") {
$0.title = "Phase"
$0.options = ["A", "B", "C", "D", "E", "F"]
}.cellUpdate { cell, row in
if (row.value != nil) {
cell.detailTextLabel?.text = row.value!.sort().joinWithSeparator(", ")
}
}
I also proposed a fix on the Eureka library to sort alphabetically by default. More details on https://github.com/xmartlabs/Eureka/pull/474
Update
This was fixed and released on Eureka 1.7.0 (2016.07.07)

Resources