Reputation: 953
I have an array something Like:
let responseArray : [[String : Any]] = [["id": 1, "sub_array": [["id": 2, "sub_array": [["id": 3], ["id": 4]]],["id": 5, "sub_array": [["id": 6], ["id": 7]]]]], ["id": 8, "sub_array": [["id": 9], ["id": 10]]]]
print(responseArray as! NSArray)
and I want to merge it to show in UITableView
expecting the result like :
let expectedOutput : [[String : Any]] = [["id" : 1], ["id" : 2], ["id" : 3], ["id" : 4], ["id" : 5], ["id" : 6], ["id" : 7], ["id" : 8], ["id" : 9], ["id" : 10]]
print(expectedOutput as! NSArray)
I can achieve it by using loops, but how to do it without using a loop?
Upvotes: 1
Views: 2514
Reputation: 448
Yes , You can . Swift CollectionTypes (Array , Dictionary , Set) has a massive good methods that provides a many alternative solution in compare of for-loop.
Here it is :-
We will perform 3 tasks as below :
Third and last one , We will fetch those ids that are part of sub_array's inner sub_array.
let responseArray : [[String : Any]] = [["id": 1, "sub_array": [["id": 2, "sub_array": [["id": 3], ["id": 4]]],["id": 5, "sub_array": [["id": 6], ["id": 7]]]]], ["id": 8, "sub_array": [["id": 9], ["id": 10]]]]
let arrExrernalIds = responseArray.flatMap({$0["id"] as? Int ?? 0})
print(arrExrernalIds) // output :- [1, 8]
let arrSub_ArrayIDs = responseArray.flatMap({$0["sub_array"] as? [[String:Any]] ?? []}).flatMap({$0["id"] as? Int ?? 0})
print(arrSub_ArrayIDs) // output :- [2, 5, 9, 10]
let arrSubArray_SubArrayIDs = responseArray.flatMap({$0["sub_array"] as? [[String:Any]] ?? []}).flatMap({$0["sub_array"] as? [[String:Any]] ?? []}).flatMap({$0["id"] as? Int ?? 0})
print(arrSubArray_SubArrayIDs) // output :- [3, 4, 6, 7]
var allIDs = (arrExrernalIds + arrSub_ArrayIDs + arrSubArray_SubArrayIDs).sorted()
print(allIDs) // output :- [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
var expectedOutput = [[String:Any]]()
for id in allIDs {
expectedOutput.append(["id":id])
}
print(expectedOutput) // output :- [["id": 1], ["id": 2], ["id": 3], ["id": 4], ["id": 5], ["id": 6], ["id": 7], ["id": 8], ["id": 9], ["id": 10]]
Only 4 Lines of code and you can achieve your desired Array.
Upvotes: 1
Reputation: 17844
It's certainly possible to write a flatten
function for this data structure without explicitly using for a in b
loops, but given the nature of your data, loops and recursive calls are IMHO unavoidable.
func flatten(_ array: [[String: Any]]) -> [[String: Any]] {
var result = [[String: Any]]()
array.forEach { dict in
dict.forEach { (key, val) in
if let v = val as? [[String: Any]] {
result.append(contentsOf: flatten(v))
} else {
result.append([key: val])
}
}
}
return result
}
Upvotes: 0