2014-11-20 20 views
6

Mam już kod do sortowania według 1 wartości, jak pokazano poniżej, ale zastanawiam się, jak sortować za pomocą wielu wartości? Chciałbym sortować według zestawu, a następnie przez someString.Jak sortować tablicę struktur według wielu wartości?

Jedna jest liczbą całkowitą, a jedna jest ciągiem w tym przypadku. Zastanawiałem się nad konwersją liczby całkowitej na ciąg, a następnie łącząc je, ale uważam, że musi istnieć lepszy sposób, ponieważ mogę mieć 2 liczby całkowite do sortowania według przyszłości.

struct Condition { 
    var set = 0 
    var someString = "" 
} 

var conditions = [Condition]() 

conditions.append(Condition(set: 1, someString: "string3")) 
conditions.append(Condition(set: 2, someString: "string2")) 
conditions.append(Condition(set: 3, someString: "string7")) 
conditions.append(Condition(set: 1, someString: "string9")) 
conditions.append(Condition(set: 2, someString: "string4")) 
conditions.append(Condition(set: 3, someString: "string0")) 
conditions.append(Condition(set: 1, someString: "string1")) 
conditions.append(Condition(set: 2, someString: "string6")) 

// sort 
let sorted = conditions.sorted { (lhs: Condition, rhs: Condition) -> Bool in 
    return (lhs.set) < (rhs.set) 
} 

// printed sorted conditions 
for index in 0...conditions.count-1 { 
    println("\(sorted[index].set) - \(sorted[index].someString)") 
} 

Odpowiedz

9

Jeszcze nie jestem biegły w Swift, ale podstawowa idea dla wielokrotnego kryteria sortowania jest:

let sorted = conditions.sorted { (lhs: Condition, rhs: Condition) -> Bool in 
    if lhs.set == rhs.set { 
     return lhs.someString < rhs.someString 
    } 
    return (lhs.set) < (rhs.set) 
} 
+0

Dzięki @Aaron za poprawienie kodu. – Cyrille

4

Można by porównać someString jeśli wartości set były takie same, w przeciwnym razie zastosowanie istniejące porównanie:

let sorted = conditions.sorted { (lhs: Condition, rhs: Condition) -> Bool in 
    if lhs.set == rhs.set { 
     return lhs.someString < rhs.someString 
    } else { 
     return lhs.set < rhs.set 
    } 
} 
+0

To wystarczy. Dzięki! –

+0

to działa! dzięki – Led

6

chociaż dotychczasowe odpowiedzi są perfekcyjnie w wymaganym przypadku, chciałbym postawić bardziej ogólne podejście f lub, że:


infix operator <=> { 
associativity none 
precedence 130 
} 
func <=> &ltT: Comparable>(lhs: T, rhs: T) -> NSComparisonResult { 
    return lhs < rhs ? .OrderedAscending : lhs == rhs ? .OrderedSame : .OrderedDescending 
} 
private func _sortedLexicographically&ltS: 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&ltS: 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) 
    } 
} 

stąd to dość łatwe do zrobienia uporządkowanie jak wnioskuje:


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 }]) 

Jeśli tego rodzaju stosunku do tego typu jest nieodłączną samego typu zamiast bycia jednym miejsce- sortowanie tylko trzeba, można śledzić więcej podejście stdlib-jak i rozszerzenie Comparable zamiast:


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) 

Nie byłoby inne możliwe podejście, które czyni LexicographicallyComparable Protokół, który określa, które pola mają priorytet, ale niestety nie potrafię wymyślić sposobu na ich użycie bez użycia generycznych wariantów variadic, które nie są obsługiwane w Swift jako 2.0, przy zachowaniu bezpieczeństwa typowego dla Swift. kod.

+2

To jest właściwe podejście, IMHO. Jeśli zamierzasz zdefiniować strukturę i chcesz ją porównać, to jest to struktura, która definiuje jej zamawianie. – Abizern

+0

W istocie zgadzam się. Ale wciąż mogą być przypadki, w których chcesz pokazać alternatywny porządek sortowania i chciałbyś, aby to było możliwe. Jak mówią: YMMV – DeFrenZ

+0

Dodatkowe punkty powinny zostać przyznane za wykazanie użycia Swift niestandardowych operatorów, jak również generycznych typów, aby rozwiązać ten problem! Brawo! – quickthyme

Powiązane problemy