通过从另一个数组排序来对Swift数组进行排序

时间:2017-03-27 21:30:51

标签: arrays swift sorting

假设我有一个自定义类[Player]的数组,每个数组都包含一个名为player.position的字符串属性

我还有一个名为positionOrders的任意值数组,如下所示:

let positionOrders = ["QB", "WR", "RB", "TE"]

我的目标是将[Player]排序为首先拥有所有“QB”,然后是“WR”,“RB”,最后是“TE”。

我正在做的当前方式遍历positionOrders中的每个元素,然后在内部循环遍历所有玩家以附加到新数组。但是,我无法想出一种更简单(更有效)的方法。非常感谢任何提示或指示。感谢。

8 个答案:

答案 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)

我会做什么:

  1. 创建一个以位置为键的字典,以及该位置的玩家数组作为值。 O(n),其中n是玩家数量。
  2. 循环浏览positionOrders并获取每个键(位置)的值。
  3. 以下是代码:

        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"]