6

Trying to sort an NSMutableDictionary in Swift 3, code from Swift 2 doesn't work for me anymore (various errors).

I am trying to use the following code to sort my dictionary by its values, which are floats:

var sortedDict = unsortedDict.allValues.sorted({ $0 < $1 }).flatMap({ floatedlotterydictionary[$0] })

Essentially, I want this unsorted dictionary...

{
a = "1.7";
b = "0.08";
c = "1.4";
}

...to turn into this sorted dictionary...

{
b = "0.08";
c = "1.4";
a = "1.7";
}

But using that line of code from above returns the error "argument type anyobject does not conform with type NSCopying" for the $0 < $1 part. So how can I sort a dictionary by its values in Swift 3?

(Note: That line of code came in part from this answer.)

I am using Swift 3 in Xcode 8 beta 1.

Community
  • 1
  • 1
owlswipe
  • 19,159
  • 9
  • 37
  • 82
  • A dictionary is unordered by definition. It is impossible to get your requested result as a dictionary. And don't use `NSMutableDictionary` in Swift. It is not related to the Swift `Dictionary` at all. – vadian Jul 16 '16 at 14:59
  • And yes, I understand a dictionary is unordered...but I want it ordered ;). And though it is somewhat unrelated, what's wrong with it? – owlswipe Jul 17 '16 at 00:32

2 Answers2

7

Ok. The collection methods available on a normal dictionary are still available, however the type of objects is not enforced, which adds an inherit unsafely.

In the docs the sorted takes a closure which lets us access the key and value at the same time and consider it as one element and hence sort your dictionary.

let k: NSMutableDictionary = ["a" : 1.7, "b" : 0.08, "c" : 1.4]
print(k.sorted(isOrderedBefore: { (a, b) in (a.value as! Double) < (b.value as! Double) }))

The casting is required, as the type of a.value and b.value is AnyObject. This works on my computer, running Xcode Version 8.0 beta (8S128d).

Mrwerdo
  • 388
  • 2
  • 7
  • `NSMutableDictionary` does **not** bridge to Swift `Dictionary` – vadian Jul 16 '16 at 15:01
  • I'm at a laptop now - Thanks. – Mrwerdo Jul 16 '16 at 15:03
  • 1
    The result is an array of tuples, not a dictionary. – vadian Jul 16 '16 at 15:24
  • Thanks, this is exactly what I needed! It works perfectly. – owlswipe Jul 17 '16 at 00:30
  • @vadian What are you talking about that NSMutableDictionary doesn't bridge to Dictionary? Here's some code that bridges it: `var nsmutabledictionary = NSMutableDictionary(dictionary: dictionary)` – owlswipe Jul 17 '16 at 00:31
  • @JohnRamos The other way round. Try `let md = NSMutableDictionary(dictionary: ["a" : 1, "b" : 2])` `md as [String: Int]` ... – vadian Jul 17 '16 at 04:26
  • @vadian Thank you, but I already have Mrwerdo's great answer. – owlswipe Jul 17 '16 at 21:05
  • This seems to be outdated could that be try? It seems like the swift 3 syntax is a little different now a days since I can't seem to get this working – NoSixties Jan 09 '17 at 17:03
  • The method call for `sorted(isOrderedBefore:)` has changed to `sorted(by:)` - Xcode should correct this. I'm unsure what the latest syntax is on the development branch, though I am using the latest version of Xcode (and the Swift that accompanies it). What's your specific issue? – Mrwerdo Jan 10 '17 at 04:38
4

There's also this way:

let k = ["a" : 1.7, "b" : 0.08, "c" : 1.4]

print(k.flatMap({$0}).sort { $0.0.1 < $0.1.1 })
FranMowinckel
  • 4,233
  • 1
  • 30
  • 26