syedfa
syedfa

Reputation: 2809

Sorting an array of struct objects using two parameters in Swift

I have the following code:

struct MyData {
    var company = String();
    var score:Int;
}

let data = [
    MyData(company: "smiths", score: 4 ),
    MyData(company: "lukes", score: 4),
    MyData(company: "lukes", score: 9)
]

extension MyData: CustomStringConvertible {
    var description: String {
        return "(\(company), \(score))"
    }
}

data.sorted { ($0.company, $1.score) < ($1.company, $0.score) }
print(data)

My output is:

[(smiths, 4), (lukes, 4), (lukes, 9)]

However, I want it to be the other way around:

[(lukes, 9), (lukes, 4), (smiths, 4)]

Can someone show me what it is I'm doing wrong?

Upvotes: 0

Views: 1206

Answers (3)

vadian
vadian

Reputation: 285079

You want to sort by company ascending then by score descending.

First of all – as mentioned in the comments – you have to assign the result to a new variable, print(data) prints the unsorted original array.

The sort algorithm is supposed to be

if the companies are equal sort the scores descending otherwise sort the companies ascending

let sortedData = data.sorted { ($0.company == $1.company) ? $0.score > $1.score : $0.company < $1.company}
print(sortedData)

Upvotes: 3

syedfa
syedfa

Reputation: 2809

So I discovered that my solution was almost there. Because the sorted function returns a new array, and doesn't actually sort the array it is being called on, my print statement was always printing the original collection. The solution to my problem was:

var myArray = data.sorted { ($0.company, $1.score) < ($1.company, $0.score) }
print(myArray)

Thanks very much for the help. :-)

Upvotes: 0

David Pasztor
David Pasztor

Reputation: 54706

Using the sorting rule described in comments, this is how your custom sorting function should look like:

let sorted = data.sorted(by: { this, next in
    if this.company < next.company {
        return true //first sort based on ascending company name
    } else if this.company == next.company {
        return this.score > next.score //if company name is the same, sort by descending score
    } else {
        return false //if company name is later in the alphabet, put it later in the sorted output
    }
})
print(sorted)

Output:

[(lukes, 9), (lukes, 4), (smiths, 4)]

Moreover, the code you used didn't work for two reasons: sorted returns a new array containing the sorted results, it's not a mutating function. It couldn't even work with a mutating function, since data is immutable.

Upvotes: 1

Related Questions