# Sorting arrays of structures

**URL:** <https://discourse.julialang.org/t/sorting-arrays-of-structures/18725>\
**Category:** New to Julia\
**Tags:** sort\
**Created:** [December 16, 2018, 10:06pm UTC](https://discourse.julialang.org/t/sorting-arrays-of-structures/18725 "2018-12-16T22:06:34Z")\
**Posts on this page:** 14\
**Page:** 1

<div class="post-metadata">

**Author:** ![KirillGerke](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/kirillgerke/32/11383_2.png) [@KirillGerke](https://discourse.julialang.org/u/KirillGerke)\
**Post date:** [December 16, 2018, 10:06pm UTC](https://discourse.julialang.org/t/sorting-arrays-of-structures/18725/1 "2018-12-16T22:06:34Z")

</div>

Dear All,

Could you, please, give me a hand in a sorting problem:

```julia
mutable struct Vox
    radiusR::Float64
    x::Int32
    y::Int32
    z::Int32
end

Voxels=Vector{Vox}(undef, 0)
#loop starts here to fill the arrays of Vox structures
push!(Voxels,Vox(computeRadius[j,k,i], j, k, i))
#loop ends here

sort!(Voxels, by=expression, rev=true)
#e.g., expression=getfield.(tmp, :radiusR) or any other way to extract this vector of data

```

I get an error: ERROR: MethodError: objects of type Array{Float64,1} are not callable  
Use square brackets for indexing an Array.  
I tried many ways around with sort function, but finally only one worked as described below.

Now, if i substitute the above-mentioned array of structures with a tuple of the form:  
`v=Array{Tuple{Float64,Int,Int,Int}}(undef,0); loop to fill the array: push!(v,(computeRadius[j,k,i], j, k, i)); sort!(v, by=first, rev=true)`  
and i get what i want. Is there a way to sort original array of structures in a fast and elegant fashion?

---

<div class="post-metadata">

**Author:** ![rdeits](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/rdeits/32/286_2.png) [@rdeits](https://discourse.julialang.org/u/rdeits)\
**Post date:** [December 16, 2018, 10:29pm UTC](https://discourse.julialang.org/t/sorting-arrays-of-structures/18725/2 "2018-12-16T22:29:28Z")

</div>

By the way, you’ll be more likely to get useful help if you post code that actually works (or at least actually reproduces the error you’re asking about). Currently, your code relies on `computeRadius`, `i`, `j`, `k`, and `expression`, which are all undefined, so we have to guess what you mean in order to be helpful.

But I think what you want is something like:

```julia
julia> sort!(Voxels, by = v -> v.radiusR, rev=true)
2-element Array{Vox,1}:
 Vox(2.0, 2, 3, 4)
 Vox(1.0, 2, 3, 4)

```

The `by` argument takes a function, so in this case I’ve used an [anonymous function](https://docs.julialang.org/en/v1/manual/functions/index.html#man-anonymous-functions-1).

---

<div class="post-metadata">

**Author:** ![Raf](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/raf/32/3383_2.png) [@Raf](https://discourse.julialang.org/u/Raf)\
**Post date:** [December 17, 2018, 9:26am UTC](https://discourse.julialang.org/t/sorting-arrays-of-structures/18725/3 "2018-12-17T09:26:40Z")

</div>

I would normally just define `isless(::Vox, ::Vox)`. Then any kind of sorting problem should just work without needing the anonymous function.

```julia
julia> mutable struct Vox
           radiusR::Float64
           x::Int32
           y::Int32
           z::Int32
       end

julia> import Base: isless

julia> isless(a::Vox, b::Vox) = isless(a.radiusR, b.radiusR)
isless (generic function with 67 methods)

julia> xs = [Vox(x, 1,2,3) for x = 10.0:-1.0:1.0]
10-element Array{Vox,1}:
 Vox(10.0, 1, 2, 3)
 Vox(9.0, 1, 2, 3) 
 Vox(8.0, 1, 2, 3) 
 Vox(7.0, 1, 2, 3) 
 Vox(6.0, 1, 2, 3) 
 Vox(5.0, 1, 2, 3) 
 Vox(4.0, 1, 2, 3) 
 Vox(3.0, 1, 2, 3) 
 Vox(2.0, 1, 2, 3) 
 Vox(1.0, 1, 2, 3) 

julia> sort!(xs)
10-element Array{Vox,1}:
 Vox(1.0, 1, 2, 3) 
 Vox(2.0, 1, 2, 3) 
 Vox(3.0, 1, 2, 3) 
 Vox(4.0, 1, 2, 3) 
 Vox(5.0, 1, 2, 3) 
 Vox(6.0, 1, 2, 3) 
 Vox(7.0, 1, 2, 3) 
 Vox(8.0, 1, 2, 3) 
 Vox(9.0, 1, 2, 3) 
 Vox(10.0, 1, 2, 3)

```

---

<div class="post-metadata">

**Author:** ![KirillGerke](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/kirillgerke/32/11383_2.png) [@KirillGerke](https://discourse.julialang.org/u/KirillGerke)\
**Post date:** [December 17, 2018, 8:08pm UTC](https://discourse.julialang.org/t/sorting-arrays-of-structures/18725/4 "2018-12-17T20:08:37Z")

</div>

Thank you, Raf! This also worked perfectly.  
However, i do have some additional question if you do not mind:

Just to understand Julia better, did you do here something we could call overloading isless and adding sorting as a private function of the Vox class (from C++ perspective)?

---

<div class="post-metadata">

**Author:** ![KirillGerke](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/kirillgerke/32/11383_2.png) [@KirillGerke](https://discourse.julialang.org/u/KirillGerke)\
**Post date:** [December 17, 2018, 8:08pm UTC](https://discourse.julialang.org/t/sorting-arrays-of-structures/18725/5 "2018-12-17T20:08:38Z")

</div>

My apologies, I actually tried to describe the problem as brief as possible, the code to fill in the array has nothing to do with the sorting problem. But i shall consider copying the whole code next time if this is more useful…

Thank you very much, this solution worked just fine!

---

<div class="post-metadata">

**Author:** ![alejandromerchan](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/alejandromerchan/32/10500_2.png) [@alejandromerchan](https://discourse.julialang.org/u/alejandromerchan)\
**Post date:** [December 17, 2018, 9:16pm UTC](https://discourse.julialang.org/t/sorting-arrays-of-structures/18725/6 "2018-12-17T21:16:27Z")

</div>

This is **multiple dispatch** at work. You created your own type (_Vox_), and overloaded the definition of the isless function to work with elements from your type. I don’t know how that compares to C++

---

<div class="post-metadata">

**Author:** ![DNF](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/dnf/32/10191_2.png) [@DNF](https://discourse.julialang.org/u/DNF)\
**Post date:** [December 17, 2018, 9:20pm UTC](https://discourse.julialang.org/t/sorting-arrays-of-structures/18725/7 "2018-12-17T21:20:47Z")

</div>

> [@KirillGerke](#):
>
> But i shall consider copying the whole code next time if this is more useful…

That is not really necessary. The thing to do is to make a _minimal_ working example (or non-working, as the case may be), that is, make an example which is as simple as possible, but demonstrates what you want help with.

Here’s a MnWE, borrowing from @Raf and you:

```julia
mutable struct Vox
    radiusR::Float64
    x::Int32
    y::Int32
    z::Int32
end

xs = [Vox(x, 1,2,3) for x = 10.0:-1.0:1.0]
sort!(xs, by=getfield.(xs, :radiusR), rev=true)

```

together with the error message.

BTW: are you sure you need `Vox` to be mutable? Just curious, but small structs like these are often good candidates to be immutable, potentially with much better performance.

---

<div class="post-metadata">

**Author:** ![foobar\_lv2](https://avatars.discourse-cdn.com/v4/letter/f/ee59a6/32.png) [@foobar\_lv2](https://discourse.julialang.org/u/foobar_lv2)\
**Post date:** [December 17, 2018, 9:56pm UTC](https://discourse.julialang.org/t/sorting-arrays-of-structures/18725/8 "2018-12-17T21:56:04Z")

</div>

> [@KirillGerke](#):
>
> Just to understand Julia better, did you do here something we could call overloading isless and adding sorting as a private function of the Vox class (from C++ perspective)?

For homogeneous vectors, this really works entirely the same way as in [C++](http://www.cplusplus.com/reference/algorithm/sort/): You pass a singleton object (`Function` object) in the by parameter that does the comparisons; dispatch is at compile time and hence comparisons can be inlined. Only that in julia, there is a `Base.isless` that is used by default, and holds a julia “Function”, which is basically a bunch of compiled julia methods (C functions); when your `sort(arr::Vector{T})` is compiled (jitted), then the correct method is selected.

You don’t need to have public/private/virtual isless methods attached to your type in C++ either.

That being said, I prefer the julia syntax for this kind of thing. For heterogenous arrays, I’d get a headache trying to get this right in C++.

---

<div class="post-metadata">

**Author:** ![Raf](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/raf/32/3383_2.png) [@Raf](https://discourse.julialang.org/u/Raf)\
**Post date:** [December 17, 2018, 10:28pm UTC](https://discourse.julialang.org/t/sorting-arrays-of-structures/18725/9 "2018-12-17T22:28:20Z")

</div>

Not much to add. But writing a minimum working example lets other people run your code, understand the problem, and make changes without doing too much work themselves.

In terms of the “overloading” in Julia it is best described as adding a method to the Base function `isless` for your custom type Vox. Multiple dispatch will choose your `isless` method from the 67 possible methods when `isless(::Vox, ::Vox)` is called.

---

<div class="post-metadata">

**Author:** ![Tim\_Lavers](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tim_lavers/32/9097_2.png) [@Tim\_Lavers](https://discourse.julialang.org/u/Tim_Lavers)\
**Post date:** [September 17, 2019, 7:06am UTC](https://discourse.julialang.org/t/sorting-arrays-of-structures/18725/10 "2019-09-17T07:06:02Z")

</div>

Thanks for this useful example. Suppose we wanted to compare Vox objects by radius, as you have done, but then break ties by comparing x, then y, then z values. Is there an idiomatic way of doing this?

---

<div class="post-metadata">

**Author:** ![hendri54](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/hendri54/32/9621_2.png) [@hendri54](https://discourse.julialang.org/u/hendri54)\
**Post date:** [September 17, 2019, 3:42pm UTC](https://discourse.julialang.org/t/sorting-arrays-of-structures/18725/11 "2019-09-17T15:42:58Z")

</div>

Extend `isless` to incorporate the tie breaking.

---

<div class="post-metadata">

**Author:** ![rdeits](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/rdeits/32/286_2.png) [@rdeits](https://discourse.julialang.org/u/rdeits)\
**Post date:** [September 17, 2019, 4:33pm UTC](https://discourse.julialang.org/t/sorting-arrays-of-structures/18725/12 "2019-09-17T16:33:08Z")

</div>

You can either implement that tie-breaking inside your `isless` implementation, or you can rely on the fact that `Tuple`s already support this kind of sorting behavior. For example, we can use this to sort a `Person` struct by last name, then by first name:

```julia
julia> struct Person
         firstname::String
         lastname::String
         age::Int
       end

julia> people = [Person("John", "Smith", 20), Person("Jane", "Smith", 22), Person("John", "Aaronson", 23)]
3-element Array{Person,1}:
 Person("John", "Smith", 20)   
 Person("Jane", "Smith", 22)   
 Person("John", "Aaronson", 23)

julia> sort(people, by = p -> (p.lastname, p.firstname))
3-element Array{Person,1}:
 Person("John", "Aaronson", 23)
 Person("Jane", "Smith", 22)   
 Person("John", "Smith", 20) 

```

---

<div class="post-metadata">

**Author:** ![tamasgal](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tamasgal/32/27946_2.png) [@tamasgal](https://discourse.julialang.org/u/tamasgal)\
**Post date:** [September 17, 2019, 5:46pm UTC](https://discourse.julialang.org/t/sorting-arrays-of-structures/18725/13 "2019-09-17T17:46:12Z")

</div>

Which of course works the same when extending `isless` 😉

```nohighlight
julia> import Base: isless

julia> isless(lhs::Person, rhs::Person) = isless((lhs.lastname, lhs.firstname), (rhs.lastname, rhs.firstname))
isless (generic function with 42 methods)

julia> people = ...

julia> sort(people)
3-element Array{Person,1}:
 Person("John", "Aaronson", 23)
 Person("Jane", "Smith", 22)
 Person("John", "Smith", 20)

```

---

<div class="post-metadata">

**Author:** ![Tim\_Lavers](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tim_lavers/32/9097_2.png) [@Tim\_Lavers](https://discourse.julialang.org/u/Tim_Lavers)\
**Post date:** [September 17, 2019, 8:54pm UTC](https://discourse.julialang.org/t/sorting-arrays-of-structures/18725/14 "2019-09-17T20:54:24Z")

</div>

Thanks to you both, @rdeits and @tamasgal! I think this will turn my ten lines of horrible code into a one-liner that is much clearer.
