Even though the previous answers are perfectly fine in the requested case, I'd like to put a more general approach for that:
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)
}
}
from here it's quite easy to do an ordering like requested:
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 }])
If this kind of comparison for that type is intrinsic to the type itself instead of being an one place-only sorting you need, you can follow the more stdlib-like approach and extending Comparable instead:
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)
There would be another possible approach which is making a LexicographicallyComparable protocol which says which Comparable fields and in which priority they do have, but unfortunately I can't think of a way to make it without using variadic generics, which are not supported in Swift as 2.0, while maintaining the type safety typical to Swift code.