Reputation: 99
Good day, I'm using new language Apple Swift and using the NSArray:
[
{
"Section" : "Title1",
"Items" :
[
{"Nr" : "101"},
{"Nr" : "201"},
{"Nr" : "301"},
{"Nr" : "401"}
]
},
{
"Section" : "Title2",
"Items" :
[
{"Nr" : "102"},
{"Nr" : "202"},
{"Nr" : "302"}
]
},
{
"Section" : "Title3",
"Items" :
[
{"Nr" : "1102"},
{"Nr" : "2102"},
{"Nr" : "3102"}
]
}
]
I want to use search, and display only content what is found
As I understand I have to use the "filteredArrayUsingPredicate" and NSPredicate in swift, so my sample is:
var arr:NSArray = [...] // My array sample goes here
var pre:NSPredicate = NSPredicate(format: "ANY Items.Nr BEGINSWITH[c] %@", argumentArray: ["20"]) // We a going to search "20" in /Items/Nr
var result:NSArray = arr.filteredArrayUsingPredicate(pre)
This is working correct but result is not what I need:
result =
[
{
"Section" : "Title1",
"Items" :
[
{"Nr" : "101"},
{"Nr" : "201"},
{"Nr" : "301"},
{"Nr" : "401"}
]
},
{
"Section" : "Title2",
"Items" :
[
{"Nr" : "102"},
{"Nr" : "202"},
{"Nr" : "302"}
]
}
]
It is display me all section what is contains Imtes with Nr started with "20"
And my question is how to do filter also in Items? The result what I need is have to be:
result =
[
{
"Section" : "Title1",
"Items" :
[
{"Nr" : "201"}
]
},
{
"Section" : "Title2",
"Items" :
[
{"Nr" : "202"}
]
}
]
I tried to use the SUBQUERY:
"SUBQUERY(Items, $x, $x.Nr BEGINSWITH[c] %@).@count > 0"
But this return me the same, if it can calculate the Items, then I thought that it can display me Items/Nr what I found, but I dont know how to write this correct. :)
Upvotes: 3
Views: 1678
Reputation: 77621
Oh, hang on. I just re-read your question, editing now
To answer your requirement of filtering the sub arrays. Your data model is getting far too complex to still be using generic objects. You should think about setting up an actual data structure with custom objects. You can then offload a lot of the work to these objects instead of putting all the work in one place.
Just trying to find the best way to do this (without a custom data model).
P.S. make a custom data model :)
OK, here we go
I made this a lot easier by wrapping your generic data up into a struct...
struct Item {
let section: String
let items: [[String: String]]
}
It still feels wrong having an array of dictionaries where each dictionary has only one key and it's always the same. Really it should just be an array of strings.
Anyway...
Create the array like so...
let items: [Item] = [
Item(section: "Title1", items: [["Nr" : "101"], ["Nr" : "201"], ["Nr" : "301"], ["Nr" : "401"]]),
Item(section: "Title2", items: [["Nr" : "102"], ["Nr" : "202"], ["Nr" : "302"]]),
Item(section: "Title3", items: [["Nr" : "1102"], ["Nr" : "2102"], ["Nr" : "3102"]])
]
Or from your data however you have it stored.
Then filter and map it into a new array...
let filteredMappedArray = items.filter {
// this filters the array so that only its containing "20..." are in it.
for dictionary in $0.items {
if let numberString = dictionary["Nr"] {
if (numberString.hasPrefix("20")) {
return true
}
}
}
return false
}.map {
// This maps the array and removes anything that isn't "20..." from the items.
Item(section: $0.section, items: $0.items.filter {
numberDictionary in
if let numberString = numberDictionary["Nr"] {
return numberString.hasPrefix("20")
}
return false
})
}
Then I logged the result...
for item in filteredMappedArray {
println("Section: \(item.section) - Items: \(item.items)")
}
And got this result...
Section: Title1 - Items: [[Nr: 201]]
Section: Title2 - Items: [[Nr: 202]]
There may be better/simpler way to combine everything into one function but this is the easiest way I could find.
If you can change your dictionary array thing...
If item can be defined as...
struct Item {
let section: String
let items: [String]
}
Then the filter-map function would become...
let filteredMappedArray = items.filter {
// this filters the array so that only its containing "20..." are in it.
for numberString in $0.items {
if (numberString.hasPrefix("20")) {
return true
}
}
return false
}.map {
// This maps the array and removes anything that isn't "20..." from the items.
Item(section: $0.section, items: $0.items.filter {$0.hasPrefix("20")})
}
By changing that dictionary array to just an array of strings you're removing a layer of complexity that isn't necessary.
Upvotes: 1