I already have code to sort by 1 value as shown below, but I'm wondering how to sort using multiple values? I would like to sort by set and then by someString.
One is an integer, and one is a string in this case. I had considered converting the integer to a string and then concatenating them, but thought there must be a better way because I may have 2 integers to sort by in the future.
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)")
}
Sort an array of objects by multiple properties in JavaScript 1 Suppose, we have an array of objects like this − 2 We are required to sort the above array on the following criteria − 3 If dnf is true, 4 If issue is true, 5 Rest should be sorted by score, and if the scores are equal, by id
In Structure sorting, all the respective properties possessed by the structure object are sorted on the basis of one (or more) property of the object. In this example, marks of students in different subjects are provided by user.
In the case of Array of Structs, the column can be selected directly and it will result in only one row: As above, there is only one row with multiple values for each Struct key. For example, address_history.status has three values [“current”, “previous”, “birth”].
Arrays in BigQuery, like in any other language, are a collection of elements of the same data type. For example, this is what an Array address_history might look like: A struct is a data type that has attributes in key-value pairs, just like a dictionary in Python.
I'm not yet proficient in Swift, but the basic idea for a multiple-criteria sort is:
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)
}
Even though the previous answers are perfectly fine in the requested case, I'd like to put a more general approach for that:
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's quite easy to do an ordering like 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 kind of comparison for that type is intrinsic to the type itself instead of being an one place-only sorting you need, you can follow the more stdlib-like approach and extending 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 which is making a LexicographicallyComparable
protocol which says which Comparable
fields and in which priority they do have, but unfortunately I can't think of a way to make it without using variadic generics, which are not supported in Swift as 2.0, while maintaining the type safety typical to Swift code.
You would compare someString
if the set
values were the same, otherwise, use your existing comparison:
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
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With