【问题标题】:Swift: sort dictionary (by keys or by values) and return ordered array (of keys or values)Swift:排序字典(按键或按值)并返回有序数组(键或值)
【发布时间】:2016-01-23 20:38:51
【问题描述】:

我有一个字典,我需要从中派生一个键数组和一个值数组,该数组按键或值排序。

我的用例是一个文件夹列表。字典包含文件夹名称(键)和文件夹中的项目数(值)。我想按键名(A 到 Z 或 Z 到 A)以及计数大小(从大到小或从小到大)进行排序。

在 Swift 中对键进行排序很容易。但我诉诸迭代来提供排序的值列表。这看起来不像 Swift 做事的方式,但我对 Swift 中的 map / sort / etc. 的理解还不够好,无法让我看到更聪明的方式。

谁能解释一个聪明而简洁的 Swift 方法来实现这个目标?

我当前的代码是:

let dictionary = ["Alpha" : 24, "Beta" : 47, "Gamma" : 12, "Delta" : 33]

enum FolderOrder : Int {
    case AlphaAtoZ
    case AlphaZtoA
    case SizeLargeToSmall
    case SizeSmallToLarge
}

func folderList(fromDictionary: [String: Int], orderedBy : FolderOrder = .AlphaAtoZ) -> [String] {
    switch orderedBy {
    case .AlphaAtoZ:
        return fromDictionary.keys.sort() {$0 < $1}

    case .AlphaZtoA:
        return fromDictionary.keys.sort() {$1 < $0}

    case .SizeSmallToLarge:
        return fromDictionary.keys.sort(){fromDictionary[$0] < fromDictionary [$1]}

    case .SizeLargeToSmall:
        return fromDictionary.keys.sort(){fromDictionary[$1] < fromDictionary [$0]}
    }
}

func folderCounts(fromDictionary: [String: Int], orderedBy : FolderOrder = .AlphaAtoZ) -> [Int]
{
    let orderedKeys = folderList(fromDictionary, orderedBy: orderedBy)
    var orderedValues = [Int]()

    for key in orderedKeys {
        orderedValues.append(fromDictionary[key] ?? 0)
    }

    return orderedValues
}

folderList(dictionary, orderedBy: .AlphaAtoZ)
// ["Alpha", "Beta", "Delta", "Gamma"]

folderList(dictionary, orderedBy: .AlphaZtoA)
// ["Gamma", "Delta", "Beta", "Alpha"]

folderList(dictionary, orderedBy: .SizeSmallToLarge)
// ["Gamma", "Alpha", "Delta", "Beta"]

folderList(dictionary, orderedBy: .SizeLargeToSmall)
//["Beta", "Delta", "Alpha", "Gamma"]

folderCounts(dictionary, orderedBy: .AlphaAtoZ)
// [24, 47, 33, 12]

folderCounts(dictionary, orderedBy: .SizeLargeToSmall)
// [47, 33, 24, 12]

更新

感谢两个有用的答案,尤其是@nRewik,我简化了我的代码并提高了我对 Swift 的理解。

修改后的代码,用 cmets 拼出我最初不清楚的内容,因此可能对其他人有所帮助:

let dictionary = ["Alpha" : 24, "Beta" : 47, "Gamma" : 12, "Delta" : 33]

enum FolderOrder {
    case AlphaAtoZ
    case AlphaZtoA
    case SizeLargeToSmall
    case SizeSmallToLarge
}

func folderListAndCounts(fromDictionary: [String: Int], orderedBy : FolderOrder = .AlphaAtoZ) -> ([String], [Int]) {

    var sortedDictionary : [(String, Int)]

    switch orderedBy {

    // The closure when sort() is applied to a dictionary takes two tuples as parameters
    // where the tuples are of the form (key, value). The first tuple can be accessed as $0.
    // Its key can be accessed as $0.0 and its value as $0.1

    case .AlphaAtoZ:
        sortedDictionary = fromDictionary.sort{ $0.0 < $1.0 } // item(n).key < item(n+1).key
    case .AlphaZtoA:
        sortedDictionary = fromDictionary.sort{ $0.0 > $1.0 } // item(n).key > item(n+1).key
    case .SizeSmallToLarge:
        sortedDictionary = fromDictionary.sort{ $0.1 < $1.1 } // item(n).value < item(n+1).value
    case .SizeLargeToSmall:
        sortedDictionary = fromDictionary.sort{ $0.1 > $1.1 } // item(n).value < item(n+1).value
    }

    // The sorted dictionary has the type: [(String, Int)], i.e. it's an array of tuples.
    // The closure when map is applied to an array of tuples is a tuple. The tuple can be
    // accessed as $0. Its key can be accessed as $0.0 and its value as $0.1

    let sortedKeys = sortedDictionary.map{$0.0}
    let sortedValues = sortedDictionary.map{$0.1}

    // Returns a tuple (arrayOfKeys, arrayOfValues)
    return (sortedKeys, sortedValues)
}

let (keys, counts) = folderListAndCounts(dictionary, orderedBy: .SizeSmallToLarge)

【问题讨论】:

    标签: arrays swift sorting dictionary


    【解决方案1】:

    这个呢?这会更改您的代码以对 Dictionary 条目进行排序,然后再获取键或值。

    let dictionary = ["Alpha" : 24, "Beta" : 47, "Gamma" : 12, "Delta" : 33]
    
    enum FolderOrder : Int {
      case AlphaAtoZ
      case AlphaZtoA
      case SizeLargeToSmall
      case SizeSmallToLarge
    }
    
    func entryList(fromDictionary: [String: Int], orderedBy : FolderOrder = .AlphaAtoZ) -> [(String, Int)] {
      switch orderedBy {
      case .AlphaAtoZ:
        return fromDictionary.sort { $0.0 < $1.0 }
    
      case .AlphaZtoA:
        return fromDictionary.sort { $0.0 > $1.0 }
    
      case .SizeSmallToLarge:
        return fromDictionary.sort { $0.1 < $1.1 }
    
      case .SizeLargeToSmall:
        return fromDictionary.sort { $0.1 > $1.1 }
      }
    }
    
    func folderList(fromDictionary: [String: Int], orderedBy : FolderOrder = .AlphaAtoZ) -> [String] {
      return entryList(fromDictionary, orderedBy: orderedBy).map { $0.0 }
    }
    
    func folderCounts(fromDictionary: [String: Int], orderedBy : FolderOrder = .AlphaAtoZ) -> [Int] {
      return entryList(fromDictionary, orderedBy: orderedBy).map { $0.1 }
    }
    
    folderList(dictionary, orderedBy: .AlphaAtoZ)
    // ["Alpha", "Beta", "Delta", "Gamma"]
    
    folderList(dictionary, orderedBy: .AlphaZtoA)
    // ["Gamma", "Delta", "Beta", "Alpha"]
    
    folderList(dictionary, orderedBy: .SizeSmallToLarge)
    // ["Gamma", "Alpha", "Delta", "Beta"]
    
    folderList(dictionary, orderedBy: .SizeLargeToSmall)
    //["Beta", "Delta", "Alpha", "Gamma"]
    
    folderCounts(dictionary, orderedBy: .AlphaAtoZ)
    // [24, 47, 33, 12]
    
    folderCounts(dictionary, orderedBy: .SizeLargeToSmall)
    // [47, 33, 24, 12]
    

    【讨论】:

      【解决方案2】:

      函数式编程风格怎么样?

      typealias DictSorter = ((String,Int),(String,Int)) -> Bool
      
      let alphaAtoZ: DictSorter = { $0.0 < $1.0 }
      let alphaZtoA: DictSorter = { $0.0 > $1.0 }
      let sizeSmallToLarge: DictSorter = { $0.1 < $1.1 }
      let sizeLargeToSmall: DictSorter = { $0.1 > $1.1 }
      
      // selector
      let listSelector: (String,Int)->String = { $0.0 }
      let countSelector: (String,Int)->Int = { $0.1 }
      
      // Usage
      let dict = ["Alpha" : 24, "Beta" : 47, "Gamma" : 12, "Delta" : 33]
      
      let folderListByAlphaAtoZ = dict.sort(alphaAtoZ).map(listSelector)
      let folderListByAlphaZtoA = dict.sort(alphaZtoA).map(listSelector)
      let folderListBySizeSmallToLarge = dict.sort(sizeSmallToLarge).map(listSelector)
      let folderListBySizeLargeToSmall = dict.sort(sizeLargeToSmall).map(listSelector)
      
      let folderCountByAlphaAtoZ = dict.sort(alphaAtoZ).map(countSelector)
      let folderCountByAlphaZtoA = dict.sort(alphaZtoA).map(countSelector)
      let folderCountBySizeSmallToLarge = dict.sort(sizeSmallToLarge).map(countSelector)
      let folderCountBySizeLargeToSmall = dict.sort(sizeLargeToSmall).map(countSelector)
      

      【讨论】:

      • 这很好。我已经为我的代码调整了这种方法。谢谢。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2015-10-10
      • 1970-01-01
      • 2017-05-30
      • 2019-06-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多