Reputation: 43
Problem
I have an array of dictionaries as follows:
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"]
]
I need to remove all dictionaries where there is a duplicate name. For instance, I need an output of:
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"]
]
Order does not need to be preserved.
Attempted Solution
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)
}
}
}
This crashes though, I believe since I am modifying the size of arrayOfDicts, so eventually it j is larger than the size of the array.
If someone could help me out, that would be much appreciated.
Upvotes: 3
Views: 8432
Reputation: 236315
You can use a set to control which dictionaries to add to the resulting array. The approach it is very similar to the one used in these answer and this
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"]]
Upvotes: 10
Reputation: 8106
If you don't mind using an additional list:
var uniqueArray = [[String: String]]()
for item in arrayOfDicts {
let exists = uniqueArray.contains{ element in
return element["Name"]! == item["Name"]!
}
if !exists {
uniqueArray.append(item)
}
}
Upvotes: 0
Reputation: 506
Try this:
var uniqueNames = [String: [String:String] ]()
for air in arrayOfDicts {
if (uniqueNames[arr["Name"]!] == nil) {
uniqueNames[arr["Name"]!] = arr
}
}
result = Array(uniqueNames.values)
Upvotes: 0
Reputation: 77631
let uniqueArray = Array(Set(yourArrayWithDuplicates))
That should do the trick.
If you want to use just the name for uniqueness then create these as structs.
You shouldn't be doing anything with dictionaries. Much easier to work with data that makes sense.
Upvotes: 0
Reputation: 2650
Several good answers already, but it was a fun exercise, so here's my solution. I'm assuming you don't care which of the duplicate entries are kept (this will keep the last one of the dupes).
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 })
}
Upvotes: 0
Reputation: 804
Please check this answer:
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])
}
}
}
Upvotes: 1
Reputation: 7351
I definitely recommend having a new copy rather than modifying the initial array. I also create storage for names already used, so you should only need to loop once.
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
}
Upvotes: 13