Reputation: 3545
I have an initial array of filter values, for example :
let filterValues : [String] = ["1", "4"]
I try to filter an array of dictionaries, where each dictionary contains an array of 1 dictionary or more.
The form of the array is the following :
let test : [[String : AnyObject]] = [
["Objects":
[
[
"value":"1",
"test":"test"
],
[
"value":"1",
"test":"test"
],
[
"value":"1",
"test":"test"
],
[
"value":"4",
"test":"test"
],
[
"value":"2",
"test":"test"
],
[
"value":"2",
"test":"test"
]
]
],
["Objects":
[
[
"value":"4",
"test":"test"
],
[
"value":"2",
"test":"test"
],
[
"value":"2",
"test":"test"
]
]
]
]
What I want after applying the filter method on my initial test array :
[
["Objects":
[
[
"value":"1",
"test":"test"
],
[
"value":"1",
"test":"test"
],
[
"value":"1",
"test":"test"
],
[
"value":"4",
"test":"test"
]
]
],
["Objects":
[
[
"value":"4",
"test":"test"
]
]
]
]
My code in playground :
//Filter objects with matching enabled filters
let filtered = test.filter({
let currentObjects = $0["Objects"] as! [[String:AnyObject]]
let currentsObjectsFiltered = currentObjects.filter({
if let value = $0["value"] as? String {
return filterValues.contains(value)
}
return false
})
print(currentsObjectsFiltered)
return false
})
The array "currentsObjectsFiltered
" is well filtered with the required values. But I want the original "filtered
" array with the structure of the test
array, not a new array which is simply filtered with the new objects. I don't know what to do with my filtered array "currentsObjectsFiltered
"
I think that I must use it now that I have the objects sorted, but how...
EDIT
currentsObjectsFiltered
output :
[["value": 1, "test": test], ["value": 1, "test": test], ["value": 1, "test": test], ["value": 1, "test": test], ["value": 4, "test": test], ["value": 4, "test": test]]
[["value": 1, "test": test], ["value": 1, "test": test], ["value": 1, "test": test], ["value": 1, "test": test], ["value": 4, "test": test], ["value": 4, "test": test]]
Don't pay attention to number of results values in the output I don't have the same test array, I just post the output to show you the structure of currentsObjectsFiltered
which is well filtered.
I think I can't do it in one filter step, because the filter method is applied only to the children of the filtered array, not the children of the children. So I can just filter the "Objects
" according a statement, I can't filter the children of "Objects
" dictionaries, anybody can confirm that ?
Any help ? Thanks.
Upvotes: 0
Views: 656
Reputation: 299275
This is possible, but the types are very annoying to work with. If you're finding yourself creating new AnyObject
types, then you're almost certainly approaching the problem wrong. AnyObject
mostly exists so you can deal with id
types that come back from Cocoa. It's not a general-purpose type for Swift.
If you first would convert these to a type-safe struct, then all of this is much simpler and you won't have to constantly up-and-downcast everything into AnyObject
.
Here's a simple struct that can be constructed from one of your dictionaries:
struct Object {
let value: Int
let test: String
init?(jsonDictionary: [String: String]) {
guard let
value = jsonDictionary["value"].flatMap({Int($0)}),
test = jsonDictionary["test"]
else { return nil }
self.value = value
self.test = test
}
}
Converting your whole data structure into this is straightforward:
let testArray = test.flatMap {
($0["Objects"] as? [[String: String]])?
.flatMap(Object.init)
}
Then filtering it as you desire is much easier:
let filterValues = [1, 4]
let filtered = testArray.map { objects in
return objects.filter { filterValues.contains($0.value) }
}
Even if you need the final result to involve AnyObject
, I'd still do it this way, and then write a function to serialize it back to your original AnyObject
structure. Working directly with AnyObject
is just too error-prone and complicated. As an example of converting back to the AnyObject
form, you could use a function like this:
func jsonArrayFromObjects(objectList: [[Object]]) -> [[String: AnyObject]] {
return objectList.map { objects in
["Objects": objects.map { ["value": "\($0.value)", "test": $0.test] }]
}
}
But I'd avoid this unless it were absolutely necessary. Even if you need a dictionary, it would be better to make this [[String: [[String: String]]]
rather than [[String: AnyObject]]
.
Upvotes: 2