2014-11-20 24 views
6

Ho già il codice per ordinare per 1 valore come mostrato di seguito, ma mi chiedo come ordinare utilizzando più valori? Vorrei ordinare per set e poi da someString.Come si ordina una matrice di strutture per più valori?

Uno è un numero intero e uno è una stringa in questo caso. Avevo pensato di convertire il numero intero in una stringa e poi concatenarlo, ma ho pensato che ci fosse un modo migliore perché potrei avere 2 interi da ordinare in futuro.

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

risposta

9

non sono ancora esperto in Swift, ma l'idea di base per una stampa di più criteri di ordinamento a dire:

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

Grazie a @Aaron per correggere il mio codice. – Cyrille

4

paragoneresti someString se i valori set erano gli stessi, in caso contrario, l'uso il vostro confronto esistente:

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

Questo lo fa. Grazie! –

+0

funziona! grazie – Led

6

Anche se le risposte precedenti sono perfettamente bene nel caso richiesto, mi piacerebbe mettere un approccio più generale f o che:


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

da qui è abbastanza facile da fare un ordinamento come richiesto:


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

Se questo tipo di confronto per quel tipo è intrinseca al tipo stesso, invece di essere un un posto- solo l'ordinamento è necessario, è possibile seguire l'approccio più stdlib-like e si estende Comparable invece:


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) 

ci sarebbe un altro possibile approccio che sta facendo un LexicographicallyComparable protocollo che dice quali campi Comparable e in quale priorità hanno, ma sfortunatamente non riesco a pensare a un modo per farlo senza usare generici variadici, che non sono supportati in Swift come 2.0, pur mantenendo il tipo di sicurezza tipico di Swift codice.

+2

Questo è l'approccio corretto, IMHO. Se stai per definire una struct, e vuoi essere in grado di confrontarla, è la struttura che definisce che sta ordinando – Abizern

+0

In effetti, sono d'accordo. Ma potrebbero ancora esserci casi in cui si desidera mostrare un ordine di ordinamento alternativo e si vorrebbe ciò possibile. Come si suol dire: YMMV – DeFrenZ

+0

Dovrebbero essere assegnati punti extra per aver dimostrato l'uso degli operatori personalizzati di Swift e dei generici di tipo per risolvere questo problema! Bravo! – quickthyme

Problemi correlati