2014-11-20 6 views
6

У меня уже есть код для сортировки по 1 значению, как показано ниже, но мне интересно, как сортировать, используя несколько значений? Я хотел бы сортировать по множеству, а затем по someString.Как отсортировать массив структур по нескольким значениям?

Один из них является целым числом, а один - строкой в ​​этом случае. Я рассматривал преобразование целого числа в строку, а затем конкатенацию, но думал, что должен быть лучший способ, потому что у меня может быть 2 целых числа, которые будут сортироваться в будущем.

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

ответ

9

Я не опытный в Swift, но основная идея многостраничного правило сортировки:

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

Спасибо @Aaron за исправление моего кода. – Cyrille

4

Вы бы сравнить someStringset, если значения были одинаковыми, в противном случае, использование существующее сравнение:

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

Это делает. Благодаря! –

+0

это работает! спасибо – Led

6

Даже если предыдущие ответы прекрасно в запрашиваемом случае, я хотел бы поставить более общий подход п или что:


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

отсюда довольно легко сделать заказ, как просил:


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 код.

+2

Это правильный подход, ИМХО. Если вы собираетесь определить структуру и хотите ее сравнить, это структура, которая определяет ее порядок. – Abizern

+0

Действительно, я согласен. Но могут быть случаи, когда вы хотите показать альтернативный порядок сортировки, и вы захотите этого. Как говорится: YMMV – DeFrenZ

+0

Дополнительные очки должны быть вознаграждены за то, что продемонстрировали использование пользовательских операторов Swift, а также типовые генераторы для решения этой проблемы! Браво! – quickthyme

Смежные вопросы