从Array of Dictionaries中删除重复值

时间:2018-04-17 17:18:54

标签: swift dictionary

我在swift中有一个数组,我想从重复值(带有它们的值)中删除重复的单个值,如下所示:

var myArray = [
        [
            "name": "John",
            "age": 21
        ],
        [
            "name": "Bob",
            "age": 35
        ],
        [
            "name": "Nyan",
            "age": 20
        ],
        [
            "name": "Nyan",
            "age": 20
        ]
    ]

我使用以下代码删除重复值

for i in 0...myArray.count - 1{
        if(myArray[i]["name"] as! String == "Nyan"){
                print(myArray.remove(at: i))
        }
}

print(myArray)

这不会减少myArray.count并给出致命错误:索引超出范围
期望的输出:

[
    "name": "John",
    "age": 21
],
[
    "name": "Bob",
    "age": 35
],
[
    "name": "Nyan",
    "age": 20
]

5 个答案:

答案 0 :(得分:3)

而不是删除我建议创建新数组的项目。

您还需要一个帮助程序数组来收集名称。如果names数组不包含当前名称,请将该名称添加到数组,并将项目添加到result

let myArray = [
    ["name": "John","age": 21],
    ["name": "Bob", "age": 35],
    ["name": "Nyan", "age": 20],
    ["name": "Nyan", "age": 20]]

var names = [String]()
var result = [[String:Any]]()

for item in myArray {
    let name = item["name"] as! String
    if !names.contains(name) {
        names.append(name)
        result.append(item)
    }
}

print(result)

而且 - 只是为了好玩 - 使用符合Hashable的结构的解决方案。

从数组中创建Set(使项目唯一),然后从集合中创建一个数组。

struct Person : Hashable { let name : String; let age : Int }

let myArray = [Person(name: "John", age: 21), Person(name: "Bob", age: 35), Person(name: "Nyan", age: 20), Person(name: "Nyan", age: 20)]
let result = Array(Set<Person>(myArray))

print(result)

答案 1 :(得分:1)

  

请使用过滤器或compactMap而不是For循环:

let array: [[String : Any]] = [["Name":"Alice", "Age":"15"],
                                       ["Name":"Bob", "Age":"53"],
                                       ["Name":"Cathy", "Age":"12"],
                                       ["Name":"Bob", "Age":"83"],
                                       ["Name":"Denise", "Age":"88"],
                                       ["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
        }

        print(arraySet)

答案 2 :(得分:0)

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

试试这个!

答案 3 :(得分:0)

当您在迭代数组时将删除数组的元素,该数组将与myArray.count一起使用而不会更改i

你可以试试这个:

let myArray = myArray.filter { element in
  if myArray.filter({ $0["name"] == element["name"] }).count == 1 {
    return true
  } else {
    return false
  }
}

这会过滤数组,只包含只有1个与名称匹配的元素。

答案 4 :(得分:0)

有一个内置的通用集合类型可以为您执行此操作,它被称为Set。 Sets是一个集合类型,如数组,但只存储唯一值,不对它们进行排序。根据您的使用情况,使用集合替换阵列的使用可能是有益的。但您也可以临时使用集来删除重复值,然后将集转换回数组。但是,集合要求其成员符合Hashable协议。 Hashable协议确定值是否重复。字典在某些方面非常简单,但是不要给编译器足够的信息,告诉他们包含什么来做任何有用的事情。

以下是将您的成员类型更改为符合Hashable的结构,使用集删除重复项,然后将该集转换为数组的示例。

struct Person:Hashable
{
     var name:String
     var age:Int
}

var myArray:[Person] = [
     Person( name:"John", age:21 ),
     Person( name:"Bob", age:35 ),
     Person( name:"Nyan", age:20 ),
     Person( name:"Nyan", age:20 ),
]

let mySet = Set<Person>( myArray )
myArray = Array( mySet )