Sorting by two values (basic sorting)

This is probably fairly simple. I want to sort a set of tuples first by the second value, and then by the first value, like this:

julia> a = [ rand(1:3,2) for i in 1: 5 ]
5-element Array{Array{Int64,1},1}:
 [2, 1]
 [3, 2]
 [3, 2]
 [1, 1]
 [2, 1]

julia> sort!(a, by = x -> x[2])
5-element Array{Array{Int64,1},1}:
 [2, 1]
 [1, 1]
 [2, 1]
 [3, 2]
 [3, 2]

julia> sort!(a, by = x -> x[1])
5-element Array{Array{Int64,1},1}:
 [1, 1]
 [2, 1]
 [2, 1]
 [3, 2]
 [3, 2]


The result is perfectly fine. However, I am somewhat unsure if the result of the second sorting might be dependent on the sorting algorithm used. Am I safe with that?

In this case I really don’t care about performance, but I wonder if there is a special function or syntax for this kind of thing.

It is dependent on the algorithm, but the default Julia sort algorithm is stable, which means that equal keys will be in the same order after sort as before. You can supply a function to sort that gives the relative order of two elements. See the lt keyword argument.

3 Likes

Yes, of course, that is much smarter.

Those aren’t tuples, they’re vectors, and they already sort lexicographically. Thus, we can generically have by return the list of keys in order to compare:

julia> sort!(a, by=x -> (x[1], x[2]))

Which in this case is also just:

julia> sort!(a, by=identity)

or just

julia> sort!(a)
6 Likes

Yes, sorry, in the MWE I have used vectors, but my real case is with tuples. Good to know that, anyway.

Yes, but in this case, OP wants:

sort!(a, by = x -> (x[2], x[1]))

Actually there is a isless function defined for tuples that does what I want, it seems:

julia> a = [ (rand(1:3),rand(1:3)) for i in 1: 5 ]
5-element Array{Tuple{Int64,Int64},1}:
 (1, 3)
 (1, 3)
 (1, 2)
 (3, 3)
 (2, 1)

julia> sort!(a)
5-element Array{Tuple{Int64,Int64},1}:
 (1, 2)
 (1, 3)
 (1, 3)
 (2, 1)
 (3, 3)

(I had to define a custom one because in my case the tuple was something computed from a struct, but that is another story).

Yes, that’s what sort!(a, by = x -> (x[2], x[1])) uses

1 Like