在旧的 Swift 版本(Swift 5.2.x 或更早版本)中,当枚举符合 Comparable 协议时,您需要将其 rawValue 声明为 Int 而不是 String 否则它不会'没有任何意义,因为枚举通常不是按字典顺序排序的。在 Swift 5.3 或更高版本中,如果您希望它自动合成,则不能声明任何 rawValue 类型。你可以在 Swift evolution 上查看这篇关于Synthesized Comparable conformance for enum types的帖子
选择加入综合 Comparable 一致性的枚举类型
将根据案例声明顺序与后面的案例进行比较
比以前的情况要大。只有枚举类型没有
只有 Comparable 关联的关联值和枚举类型
值将有资格获得综合一致性。后一种
的枚举将首先按案例声明顺序进行比较,然后
按有效载荷值按字典顺序排列。没有带有原始值的枚举类型
符合条件。
Swift 5.3 或更高版本
enum Kind: Comparable {
case movie, tv, trailer, genre, article
}
完成此操作后,您可以使用 custom sort 简单地对您的收藏集进行排序,我指出此问题是重复的:
extension MutableCollection where Self: RandomAccessCollection {
mutating func sort<T: Comparable>(_ predicate: (Element) -> T, by areInIncreasingOrder: (T, T) -> Bool = (<)) {
sort { areInIncreasingOrder(predicate($0),predicate($1)) }
}
}
extension Sequence {
func sorted<T: Comparable>(_ predicate: (Element) -> T, by areInIncreasingOrder: (T,T)-> Bool = (<)) -> [Element] {
sorted { areInIncreasingOrder(predicate($0),predicate($1)) }
}
}
游乐场测试:
struct Item {
let id: Int
let name: String
let kind: Kind
}
let items: [Item] = [
.init(id: 1, name: "D", kind: .tv),
.init(id: 2, name: "B", kind: .movie),
.init(id: 3, name: "F", kind: .trailer),
.init(id: 4, name: "H", kind: .genre),
.init(id: 5, name: "J", kind: .article),
.init(id: 6, name: "C", kind: .tv),
.init(id: 7, name: "A", kind: .movie),
.init(id: 8, name: "E", kind: .trailer),
.init(id: 9, name: "G", kind: .genre),
.init(id: 10, name: "I", kind: .article)]
items.sorted(\.kind) // [{id 2, name "B", movie}, {id 7, name "A", movie}, {id 1, name "D", tv}, {id 6, name "C", tv}, {id 3, name "F", trailer}, {id 8, name "E", trailer}, {id 4, name "H", genre}, {id 9, name "G", genre}, {id 5, name "J", article}, {id 10, name "I", article}]
编辑/更新
我不知道是否有更简单的方法来完成这种排序(我很想得到一些反馈)但是您可以按名称对项目进行排序,按种类分组,然后transpose您的项目。您需要使您的枚举 CaseIterable 并将其 rawValue 声明为 Int 从零开始。因此,将这些助手添加到您的项目中:
extension Collection where Element: RandomAccessCollection, Element.Indices == Range<Int> {
func transposed() -> [[Element.Element]] {
(0..<(max(\.count)?.count ?? .zero)).map {
index in compactMap { $0.indices ~= index ? $0[index] : nil }
}
}
}
extension Sequence {
func max<T: Comparable>(_ predicate: (Element) -> T) -> Element? {
self.max(by: { predicate($0) < predicate($1) })
}
}
然后:
enum Kind: Int, CaseIterable {
case movie = 0, tv, trailer, genre, article
}
let grouped: [[Item]] = items.reduce(into: .init(repeating: [], count: Kind.allCases.count)) { result, item in
result[item.kind.rawValue].append(item)
}
let transposed = grouped.map{$0.sorted(\.name)}.transposed()
print(transposed) // [[Item(id: 7, name: "A", kind: Kind.movie), Item(id: 6, name: "C", kind: Kind.tv), Item(id: 8, name: "E", kind: Kind.trailer), Item(id: 9, name: "G", kind: Kind.genre), Item(id: 10, name: "I", kind: Kind.article)], [Item(id: 2, name: "B", kind: Kind.movie), Item(id: 1, name: "D", kind: Kind.tv), Item(id: 3, name: "F", kind: Kind.trailer), Item(id: 4, name: "H", kind: Kind.genre), Item(id: 5, name: "J", kind: Kind.article)]]