Jack Amoratis Jack Amoratis - 2 months ago 7
Swift Question

Sort Swift Array of Dictionaries by Value of a Key

I am attempting to sort a Swift array which is composed of dictionaries. I have prepared a working example below. The goal is to sort the entire array by the "d" element in the dictionaries. I have prepared this working example which can be placed into a Swift project:

var myArray = Array<AnyObject>()
var dict = Dictionary<String, AnyObject>()

dict["a"] = "hickory"
dict["b"] = "dickory"
dict["c"] = "dock"
dict["d"] = 5

myArray.append(dict)

dict["a"] = "three"
dict["b"] = "blind"
dict["c"] = "mice"
dict["d"] = 6

myArray.append(dict)

dict["a"] = "larry"
dict["b"] = "moe"
dict["c"] = "curly"
dict["d"] = 2

myArray.append(dict)

println(myArray[0])
println(myArray[1])
println(myArray[2])
}


This results in the following output to the log:

{
a = hickory;
b = dickory;
c = dock;
d = 5;

}
{
a = three;
b = blind;
c = mice;
d = 6;
}
{
a = larry;
b = moe;
c = curly;
d = 2;
}


The goal is to sort the array by the "d" element, so that the above output would be changed to the following (which is based on numerical order of "d": '2, 5, 6'):

{
a = larry;
b = moe;
c = curly;
d = 2;
}
{
a = hickory;
b = dickory;
c = dock;
d = 5;
}
{
a = three;
b = blind;
c = mice;
d = 6;
}


There are some other questions that seem similar, but when you look at them, it becomes clear they are not addressing this. Thank you for your assistance.

Answer

To declare, if you need to keep it as AnyObject, you have to explicitly cast:

var myArray = Array<AnyObject>()
var dict = Dictionary<String, AnyObject>()

dict["a"] = ("hickory" as! AnyObject)
dict["b"] = ("dickory" as! AnyObject)
dict["c"] = ("dock" as! AnyObject)
dict["d"] = (6 as! AnyObject)

myArray.append(dict as! AnyObject)

dict["a"] = ("three" as! AnyObject)
dict["b"] = ("blind" as! AnyObject)
dict["c"] = ("mice" as! AnyObject)
dict["d"] = (5 as! AnyObject)


myArray.append(dict as! AnyObject)

dict["a"] = ("larry" as! AnyObject)
dict["b"] = ("moe" as! AnyObject)
dict["c"] = ("curly" as! AnyObject)
dict["d"] = (4 as! AnyObject)

myArray.append(dict as! AnyObject)

Without appending, you can do it like this:

var myArray: [AnyObject] = [ ([
    "a" : ("hickory" as! AnyObject),
    "b" : ("dickory" as! AnyObject),
    "c" : ("dock" as! AnyObject),
    "d" : (6 as! AnyObject)
  ] as! AnyObject), ([
    "a" : ("three" as! AnyObject),
    "b" : ("blind" as! AnyObject),
    "c" : ("mice" as! AnyObject),
    "d" : (5 as! AnyObject)
  ] as! AnyObject), ([
    "a" : ("larry" as! AnyObject),
    "b" : ("moe" as! AnyObject),
    "c" : ("curly" as! AnyObject),
    "d" : (4 as! AnyObject)
  ] as! AnyObject)
]

Which gives you the same result. Although, if only the value object in the dictionary needs to change, you don't need to cast the elements of the array:

var myArray: [Dictionary<String, AnyObject>] = [[
    "a" : ("hickory" as! AnyObject),
    "b" : ("dickory" as! AnyObject),
    "c" : ("dock" as! AnyObject),
    "d" : (6 as! AnyObject)
  ], [
    "a" : ("three" as! AnyObject),
    "b" : ("blind" as! AnyObject),
    "c" : ("mice" as! AnyObject),
    "d" : (5 as! AnyObject)
  ], [
    "a" : ("larry" as! AnyObject),
    "b" : ("moe" as! AnyObject),
    "c" : ("curly" as! AnyObject),
    "d" : (4 as! AnyObject)
  ]
]

Then, to sort, you use the sort() closure, which sorts an Array in place. The closure you supply takes two arguments (named $0 and $1), and returns a Bool. The closure should return true if $0 is ordered before $1, or false if it comes after. To do this, you've got to cast an awful lot:

//myArray starts as: [
//  ["d": 6, "b": "dickory", "c": "dock", "a": "hickory"],
//  ["d": 5, "b": "blind", "c": "mice", "a": "three"],
//  ["d": 4, "b": "moe", "c": "curly", "a": "larry"]
//]

myArray.sort{
  (($0 as! Dictionary<String, AnyObject>)["d"] as? Int) < (($1 as! Dictionary<String, AnyObject>)["d"] as? Int)
}

//myArray is now: [
//  ["d": 4, "b": "moe", "c": "curly", "a": "larry"],
//  ["d": 5, "b": "blind", "c": "mice", "a": "three"],
//  ["d": 6, "b": "dickory", "c": "dock", "a": "hickory"]
//]
Comments