从字典数组中删除重复项,Swift 3

3

问题

我有一个字典数组,如下所示:

var arrayOfDicts = [
    ["Id":"01", "Name":"Alice", "Age":"15"]
    ["Id":"02", "Name":"Bob", "Age":"53"]
    ["Id":"03", "Name":"Cathy", "Age":"12"]
    ["Id":"04", "Name":"Bob", "Age":"83"]
    ["Id":"05", "Name":"Denise", "Age":"88"]
    ["Id":"06", "Name":"Alice", "Age":"44"]
]

我需要删除所有名称重复的字典。例如,我需要以下输出:
var arrayOfDicts = [
    ["Id":"01", "Name":"Alice", "Age":"15"]
    ["Id":"02", "Name":"Bob", "Age":"53"]
    ["Id":"03", "Name":"Cathy", "Age":"12"]
    ["Id":"05", "Name":"Denise", "Age":"88"]
]

订单不需要保留。

尝试的解决方案

for i in 0..<arrayOfDicts.count
{
    let name1:String = arrayOfDicts[i]["Name"]

    for j in 0..<arrayOfDicts.count
    {
        let name2:String = arrayOfDicts[j]["Name"]

        if (i != j) && (name1 == name2)
        {
            arrayOfDicts.remove(j)
        }
    }
} 

这个代码会崩溃,我猜是因为我修改了arrayOfDicts的大小,所以最终j比数组的大小还要大。

如果有人能帮我解决这个问题,我将不胜感激。


你如何确定要保留哪个“Bob”或“Alice”?你只想保留第一个吗? - nathangitter
你的 arrayOfDicts 应该用逗号分隔。 - Dominic Bett
7个回答

13

我强烈建议使用新的副本而不是修改初始数组。我还为已经使用过的名称创建了存储空间,因此您应该只需要循环一次。

func noDuplicates(_ arrayOfDicts: [[String: String]]) -> [[String: String]] {
    var noDuplicates = [[String: String]]()
    var usedNames = [String]()
    for dict in arrayOfDicts {
        if let name = dict["name"], !usedNames.contains(name) {
            noDuplicates.append(dict)
            usedNames.append(name)
        }
    }
    return noDuplicates
}

10
你可以使用一个 set 来控制需要添加到结果数组中的字典。这种方法与这个 答案这个 的方法非常相似。
let array: [[String : Any]] = [["Id":"01", "Name":"Alice", "Age":"15"],
                                ["Id":"02", "Name":"Bob", "Age":"53"],
                                ["Id":"03", "Name":"Cathy", "Age":"12"],
                                ["Id":"04", "Name":"Bob", "Age":"83"],
                                ["Id":"05", "Name":"Denise", "Age":"88"],
                                ["Id":"06", "Name":"Alice", "Age":"44"]]

var set = Set<String>()
let arraySet: [[String: Any]] = array.compactMap {
    guard let name = $0["Name"] as? String else { return nil }
    return set.insert(name).inserted ? $0 : nil
}

arraySet   // [["Name": "Alice", "Age": "15", "Id": "01"], ["Name": "Bob", "Age": "53", "Id": "02"], ["Name": "Cathy", "Age": "12", "Id": "03"], ["Name": "Denise", "Age": "88", "Id": "05"]]

1
请检查这个答案:

var arrayOfDicts = [
    ["Id":"01", "Name":"Alice", "Age":"15"],
    ["Id":"02", "Name":"Bob", "Age":"53"],
    ["Id":"03", "Name":"Cathy", "Age":"12"],
    ["Id":"04", "Name":"Bob", "Age":"83"],
    ["Id":"05", "Name":"Denise", "Age":"88"],
    ["Id":"06", "Name":"Alice", "Age":"44"]
]

var answerArray = [[String:String]]()

for i in 0..<arrayOfDicts.count
{
    let name1 = arrayOfDicts[i]["Name"]
    if(i == 0){
        answerArray.append(arrayOfDicts[i])
    }else{
        var doesExist = false
        for j in 0..<answerArray.count
        {
            let name2:String = answerArray[j]["Name"]!
            if name1 == name2 {
                doesExist = true
            }
        }
        if(!doesExist){
            answerArray.append(arrayOfDicts[i])
        }
    }
}

0

试试这个:

var uniqueNames = [String: [String:String] ]()

for air in arrayOfDicts {
    if (uniqueNames[arr["Name"]!] == nil) {
        uniqueNames[arr["Name"]!] = arr
    }
}

result = Array(uniqueNames.values)

0

已经有几个不错的答案了,但这是一个有趣的练习,所以这是我的解决方案。我假设您不关心重复条目中保留哪个(这将保留重复项中的最后一个)。

func noDuplicates(arrayOfDicts: [[String:String]]) -> [[String:String]]
{
    var noDuplicates: [String:[String:String]] = [:]
    for dict in arrayOfDicts
    {
        if let name = dict["name"]
        {
            noDuplicates[name] = dict
        }
    }

    // Returns just the values of the dictionary
    return Array(noDuplicates.values.map{ $0 })
}

0
let uniqueArray = Array(Set(yourArrayWithDuplicates))

那应该就可以了。

如果您想要使用名称来保证唯一性,那么请将它们创建为结构体。

您不应该对字典进行任何操作。使用有意义的数据会更容易处理。


该方法不适用于提供的数据类型。 - nathangitter
1
@Nathan,就像我说的那样。将数据类型更改为适合程序需要的类型。结构体可以使这个问题变得微不足道,并且只需要很少的代码来创建和解决比这更多的问题。 - Fogmeister

0

如果您不介意使用额外的列表:

var uniqueArray = [[String: String]]()
for item in arrayOfDicts {
    let exists =  uniqueArray.contains{ element in
        return element["Name"]! == item["Name"]!
    }
    if !exists {
      uniqueArray.append(item)
    }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接