NSPredicate已过滤的数组中的子项

时间:2014-12-16 09:40:52

标签: swift filter nsarray nspredicate

美好的一天,我使用新语言Apple Swift并使用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"}
        ]
    }
]

我想使用搜索,只显示找到的内容

据我所知,我必须使用" filteredArrayUsingPredicate"和迅速的NSPredicate,所以我的样本是:

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)

这是正确的,但结果不是我需要的:

result = 
[
    {
        "Section" : "Title1",
        "Items" :
        [
            {"Nr" : "101"},
            {"Nr" : "201"},
            {"Nr" : "301"},
            {"Nr" : "401"}
        ]
    },
    {
        "Section" : "Title2",
        "Items" :
        [
            {"Nr" : "102"},
            {"Nr" : "202"},
            {"Nr" : "302"}
        ]
    }
]

显示我的所有部分包含带有Nr的Imtes以" 20"

开头

我的问题是如何在Items中进行过滤?我需要的结果必须是:

result = 
[
    {
        "Section" : "Title1",
        "Items" :
        [
            {"Nr" : "201"}
        ]
    },
    {
        "Section" : "Title2",
        "Items" :
        [
            {"Nr" : "202"}
        ]
    }
]

我尝试使用SUBQUERY:

"SUBQUERY(Items, $x, $x.Nr BEGINSWITH[c] %@).@count > 0"

但是这回复我一样,如果它可以计算物品,那么我认为它可以显示我的项目/ Nr我找到的,但我不知道如何写这个正确。 :)

1 个答案:

答案 0 :(得分:1)

哦,坚持下去。我刚刚重新阅读了您的问题,现在进行编辑

回答过滤子阵列的要求。您的数据模型变得过于复杂,无法使用通用对象。您应该考虑使用自定义对象设置实际数据结构。然后,您可以将大量工作卸载到这些对象,而不是将所有工作放在一个地方。

只是想找到最好的方法(没有自定义数据模型)。​​

P.S。制作自定义数据模型:)

好的,我们走了

通过将通用数据包装到结构中,我使这变得更容易......

struct Item {
    let section: String
    let items: [[String: String]]
}

拥有一系列词典仍然感觉不对,每个词典只有一个词,而且它总是一样的。真的,它应该只是一个字符串数组。

总之...

像这样创建数组......

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"]])
]

或者从您的数据中存储它。

然后过滤并将其映射到新数组......

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
    })
}

然后我记录了结果......

for item in filteredMappedArray {
    println("Section: \(item.section) - Items: \(item.items)")
}

得到了这个结果......

Section: Title1 - Items: [[Nr: 201]]
Section: Title2 - Items: [[Nr: 202]]

将所有内容组合成一个函数可能会有更好/更简单的方法,但这是我能找到的最简单方法。

如果您可以更改词典数组...

如果项目可以定义为......

struct Item {
    let section: String
    let items: [String]
}

然后滤镜图功能将变为......

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")})
}

通过将该字典数组更改为一个字符串数组,您可以删除一层不必要的复杂性。