Despite the fact that the previous answers in the requested case are perfectly fine, I would like to make a more general approach for this:
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 is quite easy to place an order, as 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 type of comparison for this type is internal to the type itself, and not to one sort only in place, you need to follow a more stdlib-like approach and extend 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 that the LexicographicallyComparable
protocol makes, which says which Comparable
fields and in which priority they have, but, unfortunately, I cannot think of a way to do this without using generic generics that are not supported in Swift like 2.0, while maintaining the type of security typical of Swift code.