PrinceOfBorgo
PrinceOfBorgo

Reputation: 592

Sort array of tuple over multiple indices, only one reversed in Julia

I have an Array{Tuple{Float64, Int}}, I want to sort it in reversed order according to the first entries and in straight order according to the second one.

Example: if a=[(1.0,2),(3.0,1),(2.0,3),(2.0,2)], after calling sort!(a, ...), I'd like to get [(3.0,1),(2.0,2),(2.0,3),(1.0,2)] where the first dimension is sorted from greater values to smaller ones and, when two entries are equal, the second dimension is sorted from small to big.

Upvotes: 3

Views: 498

Answers (2)

There are a couple ways to customize the sorting order, using either the lt or by keyword arguments to sort (or sort!):

  1. using lt: you define a custom "less-than" operator for tuples. You encode in this comparison operator more or less the order as you'd express it in a plain way:
julia> a=[(1.0,2),(3.0,1),(2.0,3),(2.0,2)];

julia> mylt((x1,y1), (x2,y2)) = x1>x2 || (x1==x2 && y1<y2)
mylt (generic function with 1 method)

julia> sort(a, lt=mylt)
4-element Array{Tuple{Float64,Int64},1}:
 (3.0, 1)
 (2.0, 2)
 (2.0, 3)
 (1.0, 2)

2.using by: you define a transformation that is applied to each element in the array, and by which elements are sorted:

julia> x_desc_then_y_asc((x,y)) = (-x, y)
x_desc_then_y_asc (generic function with 1 method)

julia> sort(a, by=x_desc_then_y_asc)
4-element Array{Tuple{Float64,Int64},1}:
 (3.0, 1)
 (2.0, 2)
 (2.0, 3)
 (1.0, 2)

The helper function in that variant is so short that I would make an anonymous function out of it:

julia> sort(a, by=((x,y),)->(-x,y))
4-element Array{Tuple{Float64,Int64},1}:
 (3.0, 1)
 (2.0, 2)
 (2.0, 3)
 (1.0, 2)

PS: note how "tuple destructuring" is used in all these examples in order to avoid indexing explicitly into tuples.

Upvotes: 4

Benoit Pasquier
Benoit Pasquier

Reputation: 3015

You can specify your own "isless" function for ordering, e.g.,:

julia> myisless(x,y) = (x[1]<y[1]) || (x[1]==y[1] && x[2]>y[2])
myisless (generic function with 1 method)

julia> a=[(1.0,2),(3.0,1),(2.0,3),(2.0,2)]
4-element Array{Tuple{Float64,Int64},1}:
 (1.0, 2)
 (3.0, 1)
 (2.0, 3)
 (2.0, 2)

julia> sort!(a, lt=myisless, rev=true)
4-element Array{Tuple{Float64,Int64},1}:
 (3.0, 1)
 (2.0, 2)
 (2.0, 3)
 (1.0, 2)

Or see Francois' answer which offers this and a smart alternative.

Upvotes: 3

Related Questions