即使前面的答案在请求的情况下完全没问题,我想为此提出一个更通用的方法:
infix operator <=> {
associativity none
precedence 130
}
func <=> <T: Comparable>(lhs: T, rhs: T) -> NSComparisonResult {
return lhs < rhs ? .OrderedAscending : lhs == rhs ? .OrderedSame : .OrderedDescending
}
private func _sortedLexicographically<S: SequenceType>(source: S, comparators: [(S.Generator.Element, S.Generator.Element) -> NSComparisonResult]) -> [S.Generator.Element] {
return sorted(source, { lhs, rhs in
for compare in comparators {
switch compare(lhs, rhs) {
case .OrderedAscending: return true
case .OrderedDescending: return false
case .OrderedSame: break
}
}
return false
})
}
public func sortedLexicographically<S: SequenceType>(source: S, comparators: [(S.Generator.Element, S.Generator.Element) -> NSComparisonResult]) -> [S.Generator.Element] {
return _sortedLexicographically(source, comparators)
}
extension Array {
func sortedLexicographically(comparators: [(Element, Element) -> NSComparisonResult]) -> [Element] {
return _sortedLexicographically(self, comparators)
}
}
从这里可以很容易地按照要求进行订购:
struct Foo {
var foo: Int
var bar: Int
var baz: Int
}
let foos = [Foo(foo: 1, bar: 2, baz: 3), Foo(foo: 1, bar: 3, baz: 1), Foo(foo: 0, bar: 4, baz: 2), Foo(foo: 2, bar: 0, baz: 0), Foo(foo: 1, bar: 2, baz: 2)]
let orderedFoos = foos.sortedLexicographically([{ $0.foo <=> $1.foo }, { $0.bar <=> $1.bar }, { $0.baz <=> $1.baz }])
如果该类型的这种比较是该类型本身固有的,而不是您需要的仅一个位置的排序,您可以采用更类似于 stdlib 的方法并改为扩展 Comparable:
extension Foo: Comparable {}
func == (lhs: Foo, rhs: Foo) -> Bool {
return lhs.foo == rhs.foo && lhs.bar == rhs.bar && lhs.baz == rhs.baz
}
func < (lhs: Foo, rhs: Foo) -> Bool {
let comparators: [(Foo, Foo) -> NSComparisonResult] = [{ $0.foo <=> $1.foo }, { $0.bar <=> $1.bar }, { $0.baz <=> $1.baz }]
for compare in comparators {
switch compare(lhs, rhs) {
case .OrderedAscending: return true
case .OrderedDescending: return false
case .OrderedSame: break
}
}
return false
}
let comparableOrderedFoos = sorted(foos)
还有另一种可能的方法是创建一个LexicographicallyComparable 协议,该协议说明哪些Comparable 字段以及它们具有哪些优先级,但不幸的是,我想不出不使用可变参数泛型的方法, Swift 2.0 不支持这些,同时保持 Swift 代码典型的类型安全。