![](/img/trans.png)
[英]How to sort Dictionary by keys where values are array of objects in Swift 4?
[英]Swift: sort dictionary (by keys or by values) and return ordered array (of keys or values)
我有一本字典,需要從中派生一個鍵數組和一個按鍵或值排序的值數組。
我的用例是文件夾列表。 該詞典包含文件夾名稱(鍵)和文件夾中的項目計數(值)。 我想按鍵名(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的理解。
修改后的代碼,加上注釋說明了我最初不清楚的內容,因此可能對其他人有幫助:
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)
函數式編程風格怎么樣?
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)
那這個呢? 這將更改您的代碼以對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]
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.