我为此编写了一个扩展。它非常灵活,因为它允许您定义输入按哪个字段排序,以及如何处理未根据 sortOrder 列表定义排序顺序的元素。
它很长,所以我建议你把它藏在自己的文件里:
enum UnspecifiedItemSortingPolicy {
case first
case last
case omitEntirely
case assertAllItemsHaveDefinedSorting
}
extension MutableCollection {
typealias Element = Iterator.Element
func sorted<T: Equatable>(
byOrderOf sortingMemberDeriver: @escaping (Element) -> T,
in sortingOrder: [T],
sortUnspecifiedItems unspecifiedItemSortingPolicy: UnspecifiedItemSortingPolicy = .assertAllItemsHaveDefinedSorting
) -> [Element] {
switch unspecifiedItemSortingPolicy {
case .omitEntirely: return self
.lazy
.map { (element: Element) -> (element: Element, position: Int) in
let sortingMember = sortingMemberDeriver(element)
guard let position = sortingOrder.index(of: sortingMember) else {
fatalError("Attempted to sort a collection (\(self)) containing an item (\(element)) whose ordering was not defined in the sorting order: \(sortingOrder).")
}
return (element: element, position: position)
}
.sorted{ $0.position < $1.position }
.map{ $0.element }
case .assertAllItemsHaveDefinedSorting: return self
.lazy
.flatMap { (element: Element) -> (element: Element, position: Int)? in
let sortingMember = sortingMemberDeriver(element)
return sortingOrder.index(of: sortingMember).map{ (element: element, position: $0) }
}
.sorted{ $0.position < $1.position }
.map{ $0.element }
case .first, .last:
var unspecifiedItems = Array<Element>() //items whose ordering isn't in the sortingOrder
let sortedPortion = self.flatMap { (element: Element) -> (element: Element, position: Int)? in
let sortingMember = sortingMemberDeriver(element)
guard let position = sortingOrder.index(of: sortingMember) else {
unspecifiedItems.append(element)
return nil
}
return (element: element, position: position)
}
.sorted{ $0.position < $1.position }
.map{ $0.element }
switch unspecifiedItemSortingPolicy {
case .first: return unspecifiedItems + sortedPortion
case .last: return sortedPortion + unspecifiedItems
default: fatalError("This should never happen.")
}
}
}
}
extension MutableCollection where Iterator.Element: Equatable {
func sorted(
byOrderIn sortingOrder: [Element],
sortUnspecifiedItems unspecifiedItemSortingPolicy: UnspecifiedItemSortingPolicy = .assertAllItemsHaveDefinedSorting
) -> [Element] {
return self.sorted(byOrderOf: {$0}, in: sortingOrder, sortUnspecifiedItems: unspecifiedItemSortingPolicy)
}
}
从那里开始,使用起来真的很简单和优雅:
struct Pet {
let name: String
}
let pets = [Pet(name: "Z"), Pet(name: "F"), Pet(name: "A"), Pet(name: "E")]
let petNames = ["E", "F", "Z", "A"]
let sorted = pets.sorted(byOrderOf: { $0.name }, in: petNames, sortUnspecifiedItems: .last)
sorted.forEach{ print($0) }