【问题标题】:Sort Dictionary by values in Swift在 Swift 中按值对字典进行排序
【发布时间】:2014-07-28 04:58:09
【问题描述】:

swift 中是否有 - (NSArray *)keysSortedByValueUsingSelector:(SEL)comarator 的类比?

如何在不强制转换为 NSDictionary 的情况下做到这一点?

我试过了,但这似乎不是一个好的解决方案。

var values = Array(dict.values)
values.sort({
    $0 > $1
    })

for number in values {
    for (key, value) in dict {
        if value == number {
            println(key + " : \(value)");
            dict.removeValueForKey(key);
            break
        }
    }
}

例子:

var dict = ["cola" : 10, "fanta" : 12, "sprite" : 8]
dict.sortedKeysByValues(>) // fanta (12), cola(10), sprite(8)

【问题讨论】:

标签: swift


【解决方案1】:

试试:

let dict = ["a":1, "c":3, "b":2]

extension Dictionary {
    func sortedKeys(isOrderedBefore:(Key,Key) -> Bool) -> [Key] {
        return Array(self.keys).sort(isOrderedBefore)
    }

    // Slower because of a lot of lookups, but probably takes less memory (this is equivalent to Pascals answer in an generic extension)
    func sortedKeysByValue(isOrderedBefore:(Value, Value) -> Bool) -> [Key] {
        return sortedKeys {
            isOrderedBefore(self[$0]!, self[$1]!)
        }
    }

    // Faster because of no lookups, may take more memory because of duplicating contents
    func keysSortedByValue(isOrderedBefore:(Value, Value) -> Bool) -> [Key] {
        return Array(self)
            .sort() {
                let (_, lv) = $0
                let (_, rv) = $1
                return isOrderedBefore(lv, rv)
            }
            .map {
                let (k, _) = $0
                return k
            }
    }
}

dict.keysSortedByValue(<)
dict.keysSortedByValue(>)

更新:

从 beta 3 更新到新的数组语法和排序语义。请注意,我使用 sort 而不是 sorted 来最小化数组复制。通过查看早期版本并将sort 替换为sorted 并将KeyType[] 修复为[KeyType],可以使代码更紧凑

更新到 Swift 2.2:

类型从 KeyType 更改为 KeyValueType 更改为 Value。使用新的 sort 内置到 Array 而不是 sort(Array) 注意所有这些的性能可以通过使用 sortInPlace 而不是 sort 略有提高

【讨论】:

  • 非常有趣,但不是我需要的。它只是排序的键。但我需要按值排序的键。类似 dict.sortedKeysByValues(>) --> b, c, a; dict.sortedKeysByValues( a, c, b;
  • 抱歉,误读了您所做的只是想要对键进行排序。
  • @NikeAlive 编辑做你想做的事,谢谢你的问题:)
  • 这就是我需要的。谢谢!
  • 上面的代码在 Xcode 6 Beta5 中给了我错误:“使用未声明的类型 'KeyType'”,如果我通过 Int 更改所有 KeyType/ValueType,编译器会说:“'Key' 不是第一个“func SortedKeys ...”中的“Int”子类型和“'Key'与'Int'”不同。对 Xcode6 Beta5 有任何想法或修复吗?
【解决方案2】:

也许你可以使用这样的东西:

var dict = ["cola" : 10, "fanta" : 12, "sprite" : 8]

var myArr = Array(dict.keys)
var sortedKeys = sort(myArr) {
    var obj1 = dict[$0] // get ob associated w/ key 1
    var obj2 = dict[$1] // get ob associated w/ key 2
    return obj1 > obj2
}

myArr // ["fanta", "cola", "sprite"]

【讨论】:

  • 以上在 Xcode6 Beta5 中给出了以下错误:“将 'Array' 类型的值传递给 inout 参数需要显式 '&'”。但是,如果我将其修复为“var sortedKeys = sort(&myArr)”,我会收到警告:“推断变量 'sortedKeys' 具有类型 '()',这可能是意外的”。将此修复为“var sortedKeys: () = sort(&myArr)”会为 myArr 提供指定的结果。关于我们如何对键进行排序的任何想法(如果可能的话)?另请参阅我在接受的答案中对@David 代码的评论。
  • sort(myArr),排序在 Swift 4 中不再存在。
  • 将 myArr.sorted() 用于 swift 4
【解决方案3】:

只需将其转换为 NSDictionary 然后调用该方法。在 ObjC 中使用 @selector 的任何地方都可以在 Swift 中使用字符串。所以它看起来像这样:

var dict = ["cola" : 10, "fanta" : 12, "sprite" : 8]
let sortedKeys = (dict as NSDictionary).keysSortedByValueUsingSelector("compare:")

let sortedKeys2 = (dict as NSDictionary).keysSortedByValueUsingComparator 
                  { 
                       ($0 as NSNumber).compare($1 as NSNumber) 
                  }

【讨论】:

  • Cast is too simple =) 我认为在 swift 中我可以比在 objc 中更容易地完成大多数事情
  • @NikeAlive 哈哈!也许当我们到达 swift 2.0 时……
  • 这是实际执行问题的最佳答案。按“VALUE”而不是键对字典进行排序。
【解决方案4】:

我就是这样做的——在这种情况下通过一个名为位置的键进行排序。在操场上试试这个:

var result: [[String: AnyObject]] = []
result.append(["name" : "Ted", "position": 1])
result.append(["name" : "Bill", "position": 0])
result


result = sorted(result, positionSort)

func positionSort(dict1: [String: AnyObject], dict2: [String: AnyObject]) -> Bool {
    let position1 = dict1["position"] as? Int ?? 0
    let position2 = dict2["position"] as? Int ?? 0
    return position1 < position2
}

【讨论】:

    【解决方案5】:

    这应该为您提供基于值排序的键,并且更简洁:

    var sortedKeys = Array(dict.keys).sorted(by: { dict[$0]! < dict[$1]! })
    

    【讨论】:

    • 请考虑在您的答案中添加解释,仅代码的答案不被认为是好的。
    【解决方案6】:

    按字典的值对键进行排序实际上比最初看起来要简单:

    let yourDict = ["One": "X", "Two": "B", "Three": "Z", "Four": "A"]
    let sortedKeys = yourDict.keys.sort({ (firstKey, secondKey) -> Bool in
        return yourDict[firstKey] < yourDict[secondKey]
    })
    

    就是这样!真的没有什么了。除了简单的单线形式的相同方法之外,我还没有找到更快的方法:

    let yourDict = ["One": "X", "Two": "B", "Three": "Z", "Four": "A"]
    let sortedKeys = yourDict.keys.sort { yourDict[$0] < yourDict[$1] }
    

    【讨论】:

      【解决方案7】:

      我认为这是按值对 Swift 字典进行排序的最简单方法。

      let dict = ["apple":1, "cake":3, "banana":2]
      
      let byValue = {
          (elem1:(key: String, val: Int), elem2:(key: String, val: Int))->Bool in
          if elem1.val < elem2.val {
              return true
          } else {
              return false
          }
      }
      let sortedDict = dict.sort(byValue)
      

      【讨论】:

      • 非常感谢 :) 与 swift5 一起使用(排序现在已排序(按:byValue)
      • 但是返回的值是键值对而不是字典:(
      • @MuraliDharanV 我可能不准确,因为我这些天没有开发 iOS,但在大多数编程语言中,键值对被称为字典。
      【解决方案8】:

      从 Swift 3 开始,要根据值对键进行排序,下面的方法看起来很有希望:

      var keys = Array(dict.keys)        
      keys.sortInPlace { (o1, o2) -> Bool in
          return dict[o1]! as! Int > dict[o2]! as! Int
      }
      

      【讨论】:

      • 我必须将 dict.keys 替换为 dict.allKeys 才能在 Xcode 8 beta 1 中与我的 NSMutableArray 一起使用。
      【解决方案9】:

      很多答案,这里是单行的。我喜欢它,因为它充分利用了原生 Swift 迭代函数并且不使用变量。这应该有助于优化器发挥作用。

      return dictionary.keys.sort({ $0 < $1 }).flatMap({ dictionary[$0] })
      

      注意 flatMap 的使用,因为下标字典会返回一个可选值。在实践中,这不应该返回 nil,因为我们从字典本身获取密钥。 flatMap 只是为了确保结果不是可选数组。如果您的数组的关联值应该是可选的,您可以改用map

      【讨论】:

        【解决方案10】:

        Swift 3 中的以下方式按值升序对我的字典进行排序:

        for (k,v) in (Array(dict).sorted {$0.1 < $1.1}) {
            print("\(k):\(v)")
        }
        

        【讨论】:

          【解决方案11】:

          OneLiner:

          let dict = ["b": 2, "a": 1, "c": 3]
          (Array(dict).sorted { $0.1 < $1.1 }).forEach { (k,v) in print("\(k):\(v)") }
          //Output: a:1, b:2, c:3
          

          .map 替换.forEach -> 函数式编程

          语法糖:

          extension Dictionary where Value: Comparable {
              var sortedByValue: [(Key, Value)] { return Array(self).sorted { $0.1 < $1.1} }
          }
          extension Dictionary where Key: Comparable {
              var sortedByKey: [(Key, Value)] { return Array(self).sorted { $0.0 < $1.0 } }
          }
          ["b": 2, "a": 1, "c": 3].sortedByKey // a:1, b:2, c:3
          ["b": 2, "a": 1, "c": 3].sortedByValue // a:1, b:2, c:3
          

          【讨论】:

          • 表情很烦人。
          • @vikingosegundo OK¯_(ツ)_/¯
          • @andy 感谢您的编辑,但删除了一些重要的上下文。我不得不重新编辑。无论如何,关于表情符号的 stackoverflow 规则是什么?
          • dict 未在您回答的第二部分中定义。应该改成 self 我相信
          • @Titouan de Bailleul 谢谢。已更新。
          【解决方案12】:

          如果您希望输出是元组形式的键值对数组,按值排序,则以下内容可能很有用。

          var dict = ["cola" : 10, "fanta" : 12, "sprite" : 8]
          let sortedArrByValue = dict.sorted{$0.1 > $1.1}
          print(sortedArrByValue) // output [(key: "fanta", value: 12), (key: "cola", value: 10), (key: "sprite", value: 8)]
          

          【讨论】:

            【解决方案13】:

            SWIFT 3:

            使用一些资源,我将这段精美的短代码放在一起。

            dictionary.keys.sorted{dictionary[$0]! < dictionary[$1]!}
            

            这将返回按值排序的字典键数组。它完美地工作并且当字典为空时不会抛出错误。在操场上试试这个代码:

            //: Playground - noun: a place where people can play
            
            import UIKit
            
            let dictionary = ["four": 4, "one": 1, "seven": 7, "two": 2, "three": 3]
            
            let sortedDictionary = dictionary.keys.sorted{dictionary[$0]! < dictionary[$1]!}
            
            print(sortedDictionary)
            // ["one", "two", "three", "four", "seven"]
            
            
            let emptyDictionary = [String: Int]()
            
            let emptyDictionarySorted = emptyDictionary.keys.sorted{emptyDictionary[$0]! < emptyDictionary[$1]!}
            
            print(emptyDictionarySorted)
            // []
            

            如果您想了解为什么代码使用 $0、$1 并且在“排序”方法之后甚至没有括号,请查看这篇文章 - https://stackoverflow.com/a/34785745/7107094

            【讨论】:

              【解决方案14】:

              只需一行代码即可在 Swift 4、4.2 和 Swift 5 中按值对字典进行排序:

              let sortedByValueDictionary = myDictionary.sorted { $0.1 < $1.1 }
              

              【讨论】:

              • 它适用于我在 Swift 4.1 中使用 Dictionary
              • 注:返回一个元组数组(key, value),所以如果你想要这个对象,你需要像这样读取内容:array[x].1
              【解决方案15】:

              由于 Swift 3.0 Dictionary 具有返回元组数组的 sorted(by:) 函数 ([(Key, Value)])。

              let sorted = values.sorted(by: { (keyVal1, keyVal2) -> Bool in
                  keyVal1.value > keyVal2.value
              })
              

              【讨论】:

                【解决方案16】:

                var dict = ["cola" : 10, "fanta" : 12, "sprite" : 8]

                let arr = dic.sort{ (d1,d2)-> Bool in
                if d1.value > d2.value {
                    retrn true
                }
                
                }.map { (key,value) -> Int in
                return value
                }
                

                看看一个干净的实现方式。 print("arr 是 :(arr)")

                【讨论】:

                  【解决方案17】:

                  以字典为值对字典进行排序(嵌套字典)

                     var students: [String: [String: Any?]] = ["16CSB40" : ["Name": "Sunitha", "StudentId": "16CSB40", "Total": 90], "16CSB41" : ["Name": "Vijay", "StudentId": "16CSB40", "Total": 80], "16CSB42" : ["Name": "Tony", "StudentId": "16CSB42", "Total": 95]] // Sort this dictionary with total value
                  
                      let sorted = students.sorted { (($0.1["Total"] as? Int) ?? 0) < (($1.1["Total"] as? Int) ?? 0) }
                  
                      print(sorted) //Sorted result
                  

                  【讨论】:

                    【解决方案18】:

                    按键或值对字典进行排序

                    使用 Swift 5.2 内部处理“排序”:

                    var unsortedDict = ["cola" : 10, "fanta" : 12, "sprite" : 8]
                    
                    // sorting by value
                    let sortedDictByValue = unsortedDict.sorted{ $0.value > $1.value } // from lowest to highest using ">"
                    print("sorted dict: \(sortedDictByValue)")
                    // result: "sorted dict: [(key: "fanta", value: 12), (key: "cola", value: 10), (key: "sprite", value: 8)]\n"
                    
                    // highest value
                    print(sortedDictByValue.first!.key)  // result: fanta
                    print(sortedDictByValue.first!.value)  // result: 12
                    // lowest value
                    print(sortedDictByValue.last!.key)  // result: sprite
                    print(sortedDictByValue.last!.value)  // result: 8
                    // by index
                    print(sortedDictByValue[1].key)  // result: cola
                    print(sortedDictByValue[1].value)  // result: 10
                    
                    // sorting by key
                    let sortedDictByKey = unsortedDict.sorted{ $0.key < $1.key } // in alphabetical order use "<"
                    // alternative:
                    // let sortedDictByKey = unsortedDict.sorted{ $0 < $1 }  // without ".key"
                    print("sorted dict: \(sortedDictByKey)")
                    // result: "sorted dict: [(key: "cola", value: 10), (key: "fanta", value: 12), (key: "sprite", value: 8)]\n"
                    
                    // highest value
                    print(sortedDictByKey.first!.key)  // result: cola
                    print(sortedDictByKey.first!.value)  // result: 10
                    // lowest value
                    print(sortedDictByKey.last!.key)  // result: sprite
                    print(sortedDictByKey.last!.value)  // result: 8
                    // by index
                    print(sortedDictByKey[1].key)  // result: fanta
                    print(sortedDictByKey[1].value)  // result: 12
                    

                    【讨论】:

                    • 当然!,不明白为什么这不是公认的答案
                    【解决方案19】:

                    使用它,然后使用输出键再次遍历字典。

                    extension Dictionary where Value: Comparable {
                      func sortedKeysByValue() -> [Key] {
                        keys.sorted { return self[$0]! < self[$1]! }
                      }
                    }
                    

                    ...或者如果你讨厌强制展开的话,这个:)

                    extension Dictionary where Value: Comparable {
                      func sortedKeysByValue() -> [Key] {
                        keys.sorted { (key1, key2) -> Bool in
                          guard let val1 = self[key1] else { return true }
                          guard let val2 = self[key2] else { return true }
                          return val1 < val2
                        }
                      }
                    }
                    

                    【讨论】:

                      猜你喜欢
                      • 1970-01-01
                      • 2021-08-12
                      • 2011-02-09
                      • 1970-01-01
                      • 1970-01-01
                      • 2015-07-15
                      相关资源
                      最近更新 更多