如何按多个值对结构数组进行排序?

时间:2014-11-20 13:17:59

标签: sorting swift

我已经有了按1值排序的代码,如下所示,但我想知道如何使用多个值进行排序?我想按set排序,然后按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)")
}

3 个答案:

答案 0 :(得分:11)

我还不熟悉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)
}

答案 1 :(得分:6)

尽管之前的答案在所要求的案例中完全没问题,但我想为此提出一个更通用的方法:


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)
    }
}
从这里开始按照要求进行订购非常容易:


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 :(得分:4)

如果someString值相同,您可以比较set,否则,请使用您现有的比较:

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