Here's a generic Swift 5.2 solution.
First we need to define a protocol that holds a property that is used to reorder our elements:
protocol Reorderable {
associatedtype OrderElement: Equatable
var orderElement: OrderElement { get }
}
Then we need to extend Array
with elements conforming to Reorderable
and implement our reordering function:
extension Array where Element: Reorderable {
func reorder(by preferredOrder: [Element.OrderElement]) -> [Element] {
sorted {
guard let first = preferredOrder.firstIndex(of: $0.orderElement) else {
return false
}
guard let second = preferredOrder.firstIndex(of: $1.orderElement) else {
return true
}
return first < second
}
}
}
Example
Let's assume you have defined:
struct Player {
let position: String
}
let currentPositions = ["RB", "AA", "BB", "CC", "WR", "TE"]
let players = currentPositions.map { Player(position: $0) }
Now, all you need to do is conform Player
to Reorderable
:
extension Player: Reorderable {
typealias OrderElement = String
var orderElement: OrderElement { position }
}
You can now use:
let sortedPlayers = players.reorder(by: ["QB", "WR", "RB", "TE"])
print(sortedPlayers.map { $0.position })
// ["WR", "RB", "TE", "AA", "BB", "CC"]
Original Solution
This is a generic Swift 5.2 solution based on OuSS' code and requires array elements to be Equatable.
extension Array where Element: Equatable {
func reorder(by preferredOrder: [Element]) -> [Element] {
return self.sorted { (a, b) -> Bool in
guard let first = preferredOrder.firstIndex(of: a) else {
return false
}
guard let second = preferredOrder.firstIndex(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"]