# Maximum by element in array

**URL:** <https://discourse.julialang.org/t/maximum-by-element-in-array/23584>\
**Category:** New to Julia\
**Created:** [April 26, 2019, 8:53pm UTC](https://discourse.julialang.org/t/maximum-by-element-in-array/23584 "2019-04-26T20:53:51Z")\
**Posts on this page:** 13\
**Page:** 1

<div class="post-metadata">

**Author:** ![NPWarLoNCLnJ](https://avatars.discourse-cdn.com/v4/letter/n/bc79bd/32.png) [@NPWarLoNCLnJ](https://discourse.julialang.org/u/NPWarLoNCLnJ)\
**Post date:** [April 26, 2019, 8:53pm UTC](https://discourse.julialang.org/t/maximum-by-element-in-array/23584/1 "2019-04-26T20:53:51Z")

</div>

Hey,  
I’m new to the wonderful language Julia, coming from JavaScript and Ruby.  
I have the following code:

```julia
list = []
for x = -2:2, y = -2:2
  push!(list, (x, y, x * y))
end

```

Now I want to find the element/tuple that has the highest third value. In Ruby I would use `max_by`. Is there something similar that would return `(2, 2, 4)`?  
In fact `maximum(list)` ([Base.maximum](https://docs.julialang.org/en/v1.1/base/collections/#Base.maximum)) returns that but I can’t figure out by which criteria. Is it the sum of the tuple?  
Thank you so much!

---

<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:** [April 26, 2019, 9:13pm UTC](https://discourse.julialang.org/t/maximum-by-element-in-array/23584/2 "2019-04-26T21:13:02Z")

</div>

> [@NPWarLoNCLnJ](#):
>
> Is there something similar that would return `(2, 2, 4)` ?

In default tuple comparison, the first element is most significant, and end-of-tuple is smaller than all possible elements.

Unfortunately `maximum` does not accept a `by`-keyword. You can do e.g. the following (2 lines instead of one)

```julia
julia> r=[(1,2,3), (0,5,6), (1,2,4)]
julia> reduce(r) do x,y
       x[3]>y[3] ? x : y end
(0, 5, 6)

```

Note that this has different corner-case semantics than the built-in `maximum` (how are `NaN` handled? What about `missing`? In case of elements that compare equal, which one is returned?).

---

<div class="post-metadata">

**Author:** ![stevengj](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/stevengj/32/71_2.png) [@stevengj](https://discourse.julialang.org/u/stevengj)\
**Post date:** [April 26, 2019, 9:15pm UTC](https://discourse.julialang.org/t/maximum-by-element-in-array/23584/3 "2019-04-26T21:15:44Z")

</div>

> [@foobar\_lv2](#):
>
> Unfortunately `maximum` does not accept a `by` -keyword.

> <https://github.com/JuliaLang/julia/issues/28210>
>
> Essentially the same thing that already exists for \`\`sort\`\`: an option to specif…y a selector function, so that the maximum is determined by whatever the selector function returns, but then the \`maximum\` function returns an element from the original input sequence.
> 
> For example, \`\`maximum(\[(a=1,b=2),(a=2,b=1)\], by=i-\>i.b)\`\` would return \`\`(a=1,b=2)\`\`.

---

<div class="post-metadata">

**Author:** ![mbauman](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mbauman/32/31082_2.png) [@mbauman](https://discourse.julialang.org/u/mbauman)\
**Post date:** [April 26, 2019, 9:40pm UTC](https://discourse.julialang.org/t/maximum-by-element-in-array/23584/4 "2019-04-26T21:40:32Z")

</div>

You could use the ability to transform each element to make this work (and then transform it back again afterwards):

```julia
julia> reverse(maximum(reverse, list))
(2, 2, 4)

```

Of course, this only works for this one particular example because there exists this sort of reversible transformation that sorts how you want.

---

<div class="post-metadata">

**Author:** ![piever](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/piever/32/1815_2.png) [@piever](https://discourse.julialang.org/u/piever)\
**Post date:** [April 26, 2019, 10:03pm UTC](https://discourse.julialang.org/t/maximum-by-element-in-array/23584/5 "2019-04-26T22:03:51Z")

</div>

Even though `maximum` has no `by` keyword, `partialsort` (used to sort a few entries, for example `partialsort(t, 1:3)` would find the three smallest entries) does, so you could do:

```julia
partialsort(list, 1, by = t -> t[3], rev = true)

```

as `partialsort(t, 1, rev = true)` is the same as `maximum`, but I agree it’d be nicer to just be able to do `maximum(list, by = t -> t[3])`.

---

<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:** [April 27, 2019, 7:48am UTC](https://discourse.julialang.org/t/maximum-by-element-in-array/23584/6 "2019-04-27T07:48:07Z")

</div>

Since you can do

```julia
julia> maximum(last, list)
4

```

is was going to say, just use

```julia
(_, ind) = findmax(last, list)
list[ind]

```

or

```julia
ind = argmax(last, list)
list[ind]

```

I was _very_ surprised to find that `findmax` and `argmax` do not support a function as first input. Is this a deliberate choice, or is it just not implemented?

---

<div class="post-metadata">

**Author:** ![stevengj](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/stevengj/32/71_2.png) [@stevengj](https://discourse.julialang.org/u/stevengj)\
**Post date:** [April 27, 2019, 3:53pm UTC](https://discourse.julialang.org/t/maximum-by-element-in-array/23584/7 "2019-04-27T15:53:19Z")

</div>

> [@DNF](#):
>
> I was _very_ surprised to find that `findmax` and `argmax` do not support a function as first input. Is this a deliberate choice, or is it just not implemented?

Just not implemented; if you read the issue I linked, there is general support for this kind of feature. Someone just has to do it.

---

<div class="post-metadata">

**Author:** ![NPWarLoNCLnJ](https://avatars.discourse-cdn.com/v4/letter/n/bc79bd/32.png) [@NPWarLoNCLnJ](https://discourse.julialang.org/u/NPWarLoNCLnJ)\
**Post date:** [April 27, 2019, 4:42pm UTC](https://discourse.julialang.org/t/maximum-by-element-in-array/23584/8 "2019-04-27T16:42:37Z")

</div>

Thanks so much for so many suggestions! Such an active and friendly community!

I have two remaining questions:

1. @piever, you said that `partialsort` is just for few entries. Is it because of performance? I’ll be having an array with over a thousand entries. Are the other suggestions better then?

2. Two suggestions used `maximum(~method~, list)`. The documention says the first argument of two is an `A::AbstractArray`. How is this method applied to the list a parameter of `maximum`? Or how is this concept called so that I could look that up?

---

<div class="post-metadata">

**Author:** ![ffevotte](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/ffevotte/32/6587_2.png) [@ffevotte](https://discourse.julialang.org/u/ffevotte)\
**Post date:** [April 27, 2019, 9:04pm UTC](https://discourse.julialang.org/t/maximum-by-element-in-array/23584/9 "2019-04-27T21:04:14Z")

</div>

> [@NPWarLoNCLnJ](#):
>
> Two suggestions used `maximum(~method~, list)` . The documention says the first argument of two is an `A::AbstractArray` . How is this method applied to the list a parameter of `maximum` ? Or how is this concept called so that I could look that up?

You can list all methods of the `maximum` function like so:

```julia
julia> methods(maximum)
# 11 methods for generic function "maximum":
[1] maximum(s::BitSet) in Base at bitset.jl:417
[2] maximum(r::AbstractUnitRange) in Base at range.jl:572
[3] maximum(r::AbstractRange) in Base at range.jl:574
[4] maximum(B::BitArray) in Base at bitarray.jl:1650
[5] maximum(x::SparseArrays.AbstractSparseArray{T,Ti,1} where Ti) where T<:Real in SparseArrays at /buildworker/worker/package_linux64/build/usr/share/julia/stdlib/v1.1/SparseArrays/src/sparsevector.jl:1307
[6] maximum(a::AbstractArray; dims) in Base at reducedim.jl:648
[7] maximum(::typeof(abs), x::SparseArrays.AbstractSparseArray{Tv,Ti,1} where Ti where Tv) in SparseArrays at /buildworker/worker/package_linux64/build/usr/share/julia/stdlib/v1.1/SparseArrays/src/sparsevector.jl:1329
[8] maximum(::typeof(abs2), x::SparseArrays.AbstractSparseArray{Tv,Ti,1} where Ti where Tv) in SparseArrays at /buildworker/worker/package_linux64/build/usr/share/julia/stdlib/v1.1/SparseArrays/src/sparsevector.jl:1329
[9] maximum(a) in Base at reduce.jl:487
[10] maximum(f, a::AbstractArray; dims) in Base at reducedim.jl:649
[11] maximum(f, a) in Base at reduce.jl:470

```

This might help you discover specific methods which you didn’t know about (in this case, methods 10 & 11 are what you’re looking for). Now, if you somehow get a piece of code that works (such as `mbauman`’s answer above), and would like to understand which method it uses, then:

```julia
julia> @which maximum(reverse, list)
maximum(f, a::AbstractArray) in Base at reducedim.jl:649

```

So this tells you that in this method, the second argument is the array; the first argument is not restricted to any type (but in practice should be callable). This is to allow for the special `do` syntax, which always acts on the first argument of the method.

Does that help?

---

<div class="post-metadata">

**Author:** ![stevengj](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/stevengj/32/71_2.png) [@stevengj](https://discourse.julialang.org/u/stevengj)\
**Post date:** [April 27, 2019, 9:59pm UTC](https://discourse.julialang.org/t/maximum-by-element-in-array/23584/10 "2019-04-27T21:59:35Z")

</div>

Note that a simple and fast option is always just to write a loop. There is nothing magical about standard-library functions.

---

<div class="post-metadata">

**Author:** ![piever](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/piever/32/1815_2.png) [@piever](https://discourse.julialang.org/u/piever)\
**Post date:** [April 28, 2019, 10:43am UTC](https://discourse.julialang.org/t/maximum-by-element-in-array/23584/11 "2019-04-28T10:43:22Z")

</div>

> [@NPWarLoNCLnJ](#):
>
> @piever, you said that `partialsort` is just for few entries. Is it because of performance? I’ll be having an array with over a thousand entries. Are the other suggestions better then?

I simply meant that, while `partialsort(v, n)` should give the same result as `sort(v)[n]`, it is generally faster because you don’t need to sort the whole array. Anyway, if the number of elements is in the thousands, all sensible solutions should take almost no time (I would imagine less than a millisecond).

---

<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:** [April 29, 2019, 6:52am UTC](https://discourse.julialang.org/t/maximum-by-element-in-array/23584/12 "2019-04-29T06:52:33Z")

</div>

> [@NPWarLoNCLnJ](#):
>
> ```julia
> list = [] 
> for x = -2:2, y = -2:2 
> push!(list, (x, y, x * y))
> end
> 
> ```

Maybe this is just an issue with your example, but if you care about performance at all, you should not use an untyped array (`list`):

```julia
julia> arr = [(x, y, x*y) for x in -2:2 for y in -2:2]

julia> @btime maximum(last, $list)
  1.480 μs (0 allocations: 0 bytes)

julia> @btime maximum(last, $arr)
  17.783 ns (0 allocations: 0 bytes)

```

---

<div class="post-metadata">

**Author:** ![NPWarLoNCLnJ](https://avatars.discourse-cdn.com/v4/letter/n/bc79bd/32.png) [@NPWarLoNCLnJ](https://discourse.julialang.org/u/NPWarLoNCLnJ)\
**Post date:** [April 29, 2019, 7:55am UTC](https://discourse.julialang.org/t/maximum-by-element-in-array/23584/13 "2019-04-29T07:55:12Z")

</div>

Oh, wow. That is really helpful! Thank you so much!
