假设我有一个自定义类[Player]
的数组,每个数组都包含一个名为player.position
的字符串属性
我还有一个名为positionOrders
的任意值数组,如下所示:
let positionOrders = ["QB", "WR", "RB", "TE"]
我的目标是将[Player]
排序为首先拥有所有“QB”,然后是“WR”,“RB”,最后是“TE”。
我正在做的当前方式遍历positionOrders
中的每个元素,然后在内部循环遍历所有玩家以附加到新数组。但是,我无法想出一种更简单(更有效)的方法。非常感谢任何提示或指示。感谢。
答案 0 :(得分:28)
对于小尺寸的positionOrders
,这是一种可行的方法:
let sorted = players.sorted{ positionOrders.index(of: $0.position)! < positionOrders.index(of: $1.position)! }
这是一个更复杂的解决方案,对于较大尺寸的positionOrders
let ordering = Dictionary(uniqueKeysWithValues: x.enumerated().map { ($1, $0) })
let sorted = players.sorted{ ordering[$0.position]! < ordering[$1.position]! }
这两个解决方案都假设所有可能的玩家位置都根据positionOrders有一个定义的顺序,因此他们使用!
来简洁。如果情况不是这样,请告诉我。
答案 1 :(得分:7)
根据亚历山大的回答,我已经实施了扩展来实现这一目标。
extension Array where Element == String {
func reordered() -> [String] {
let defaultOrder = ["orange", "pear", "watermelon", "grapefruit", "apple", "lemon", "tomatoes"]
return self.sorted { (a, b) -> Bool in
if let first = defaultOrder.index(of: a), let second = defaultOrder.index(of: b) {
return first < second
}
return false
}
}
let arrayToSort = ["lemon", "watermelon", "tomatoes"]
let sortedArray = arrayToSort.reordered()
print(sortedArray) // ["watermelon", "lemon", "tomatoes"]
答案 2 :(得分:4)
我喜欢单色,这是另一种:
positionOrders.compactMap { order in players.first(where: { $0.position == order })}
关于这种方法唯一需要考虑的是它具有 O(n*m)
- 或 O(positionOrders*players)
- 时间复杂度。
答案 3 :(得分:3)
这是一个基于OuSS代码的通用Swift 4解决方案,要求数组元素必须相等。
extension Array where Element: Equatable {
func reorder(by preferredOrder: [Element]) -> [Element] {
return self.sorted { (a, b) -> Bool in
guard let first = preferredOrder.index(of: a) else {
return false
}
guard let second = preferredOrder.index(of: b) else {
return true
}
return first < second
}
}
}
let currentPositions = ["RB", "AA", "BB", "CC", "WR", "TE"]
let preferredOrder = ["QB", "WR", "RB", "TE"]
let sorted = currentPositions.reorder(by: preferredOrder)
print(sorted) // ["WR", "RB", "TE", "AA", "BB", "CC"]
答案 4 :(得分:2)
我会做什么:
positionOrders
并获取每个键(位置)的值。以下是代码:
let preSortPlayerList = [Player]() // Filled with your players.
let positionOrders = ["QB", "WR", "RB", "TE"]
let dict = preSortPlayerList.reduce([String : [Player]]()) {
var map = $0
if var tmp = map[$1.position] {
tmp.append($1)
map[$1.position] = tmp
} else {
map[$1.position] = [$1]
}
return map
}
let playersArray: [Player] = positionOrders.flatMap { dict[$0] ?? [Player]() }
print("\(playersArray)")
答案 5 :(得分:1)
快速4
非常简单勤奋(随时建议和纠正我)
func reOrder(array : [String] , order : [String]) -> [String]{
//common elments in order
// order.filter{array.contains($0)}
// the rest of the array that the order doesnt specify
// array.filter{!order.contains($0)}
return order.filter{array.contains($0)} + array.filter{!order.contains($0)}
}
let list = ["A", "Z", "B", "H", "C", "T", "D", "E"]
let newOrder = ["A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L"]
print("The ordered list is ",reOrder(array: list, order: newOrder))
// The ordered list is ["A", "B", "C", "D", "E", "H", "Z", "T"]
如果有人可以将其作为泛型类型的扩展名,那会很好,我对此并不满意
答案 6 :(得分:1)
SwifterSwift 有这个实现
/// SwifterSwift: Sort an array like another array based on a key path. If the other array doesn't contain a certain value, it will be sorted last.
///
/// [MyStruct(x: 3), MyStruct(x: 1), MyStruct(x: 2)].sorted(like: [1, 2, 3], keyPath: \.x)
/// -> [MyStruct(x: 1), MyStruct(x: 2), MyStruct(x: 3)]
///
/// - Parameters:
/// - otherArray: array containing elements in the desired order.
/// - keyPath: keyPath indiciating the property that the array should be sorted by
/// - Returns: sorted array.
func sorted<T: Hashable>(like otherArray: [T], keyPath: KeyPath<Element, T>) -> [Element] {
let dict = otherArray.enumerated().reduce(into: [:]) { $0[$1.element] = $1.offset }
return sorted {
guard let thisIndex = dict[$0[keyPath: keyPath]] else { return false }
guard let otherIndex = dict[$1[keyPath: keyPath]] else { return true }
return thisIndex < otherIndex
}
}
答案 7 :(得分:-1)
基于Emily代码,我对扩展做了一些更改,因为它不会使最终在defaultOrder中不存在的元素
extension Array where Element == String {
func reordered() -> [String] {
let defaultOrder = ["lemon", "watermelon", "tomatoes"]
return self.sorted { (a, b) -> Bool in
guard let first = defaultOrder.index(of: a) else {
return false
}
guard let second = defaultOrder.index(of: b) else {
return true
}
return first < second
}
}
let arrayToSort = ["orange", "watermelon", "grapefruit", "lemon", "tomatoes"]
let sortedArray = arrayToSort.reordered()
print(sortedArray) // ["watermelon", "lemon", "tomatoes", "orange", "grapefruit"]