# Consecutive findmin and findmax

**URL:** <https://discourse.julialang.org/t/consecutive-findmin-and-findmax/94419>\
**Category:** General Usage\
**Tags:** question\
**Created:** [February 10, 2023, 5:19pm UTC](https://discourse.julialang.org/t/consecutive-findmin-and-findmax/94419 "2023-02-10T17:19:52Z")\
**Posts on this page:** 7\
**Page:** 1

<div class="post-metadata">

**Author:** ![filchristou](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/filchristou/32/26760_2.png) [@filchristou](https://discourse.julialang.org/u/filchristou)\
**Post date:** [February 10, 2023, 5:19pm UTC](https://discourse.julialang.org/t/consecutive-findmin-and-findmax/94419/1 "2023-02-10T17:19:52Z")

</div>

I want to find the index of an element after consecutive `min` and `max` operations.

I have a working code, but it’s ugly and probably inefficient since it makes unneeded iterations.  
Also it’s not flexible, in the sense it’s not super easy to change the min/max operation sequence.

Below a MWE and my code, where I basically want the element with minimum `a`. Out of these the one with maximum `b`. And out of these the one with minimum `c`

```julia
struct My
    a::Int
    b::Int
    c::Int
end
geta(my::My) = my.a
getb(my::My) = my.b
getc(my::My) = my.c

import Random
rng = Random.MersenneTwister(0)
mys = [My(x,y,z) for x in rand(rng, 1:5, 5) for y in rand(rng, 1:5, 5) for z in rand(rng, 1:5, 5)];

amin, _ = findmin(geta, mys);

aminfilter = filter(x -> geta(x) == amin, mys);
bmax, _ = findmax(getb ,aminfilter);

aminbmaxfilter = filter(x -> geta(x) == amin && getb(x) == bmax ,mys);
cmin, _ = findmin(getc ,aminbmaxfilter);

result = findfirst(x -> geta(x) == amin && getb(x) == bmax && getc(x) == cmin, mys)

```

yielding

```julia
24
julia> mys[24]
1-element Vector{My}:
 My(3, 5, 1)

```

I would love to have a simple nice expression like this:

```julia
# psedocode
findmin(getc, findmax(getb, findmin(geta, mys)))

```

How would you solve the above problem in a more elegant way?

---

<div class="post-metadata">

**Author:** ![j\_verzani](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/j_verzani/32/8551_2.png) [@j\_verzani](https://discourse.julialang.org/u/j_verzani)\
**Post date:** [February 10, 2023, 8:55pm UTC](https://discourse.julialang.org/t/consecutive-findmin-and-findmax/94419/2 "2023-02-10T20:55:20Z")

</div>

Dunno if this qualifies as elegant, but …

```julia
using SplitApplyCombine
function selectall(itr, f,r)
       d = groupview(f, itr)
       d[r(keys(d))]
end
selectall(itr, fr) = selectall(itr, fr...) # binary version
reduce(selectall, ((geta,minimum), (getb, maximum), (getc, minimum)), init=mys)

```

---

<div class="post-metadata">

**Author:** ![uniment](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/uniment/32/24532_2.png) [@uniment](https://discourse.julialang.org/u/uniment)\
**Post date:** [February 11, 2023, 12:43am UTC](https://discourse.julialang.org/t/consecutive-findmin-and-findmax/94419/3 "2023-02-11T00:43:23Z")

</div>

```julia
reduce(enumerate(mys)) do (i,x), (j,y)
    x.a > y.a && return j=>y
    x.a == y.a && begin
        x.b < y.b && return j=>y
        x.b == y.b &&
            x.c > y.c && return j=>y
    end
    i=>x
end

```

---

<div class="post-metadata">

**Author:** ![Dan](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/dan/32/42581_2.png) [@Dan](https://discourse.julialang.org/u/Dan)\
**Post date:** [February 11, 2023, 12:44am UTC](https://discourse.julialang.org/t/consecutive-findmin-and-findmax/94419/4 "2023-02-11T00:44:28Z")

</div>

Another method:

```julia
julia> Base.isless(x::My, y::My) = isless((x.a,-x.b,x.c),(y.a,-y.b,y.c))

julia> findmin(mys)
(My(3, 5, 1), 24)

```

---

<div class="post-metadata">

**Author:** ![rafael.guerra](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/rafael.guerra/32/216610_2.png) [@rafael.guerra](https://discourse.julialang.org/u/rafael.guerra)\
**Post date:** [February 11, 2023, 4:25pm UTC](https://discourse.julialang.org/t/consecutive-findmin-and-findmax/94419/5 "2023-02-11T16:25:27Z")

</div>

> [@filchristou](#):
>
> I want to find the index of an element

Check also this option:

```julia
partialsortperm(mys, 1, by = x -> (x.a, -x.b, x.c))      
24

```

---

<div class="post-metadata">

**Author:** ![filchristou](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/filchristou/32/26760_2.png) [@filchristou](https://discourse.julialang.org/u/filchristou)\
**Post date:** [February 14, 2023, 7:11am UTC](https://discourse.julialang.org/t/consecutive-findmin-and-findmax/94419/6 "2023-02-14T07:11:24Z")

</div>

this function does exactly what I want! Thanks!

The answer from @Dan is also very elegant but it appears not to be flexible… I wish there was a `by` argument in the `findmin` function. Overloading `Base.isless` everytime I need a different functionality doesn’t work nicely.

Thanks everybody for the nice solutions.

---

<div class="post-metadata">

**Author:** ![aplavin](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/aplavin/32/222056_2.png) [@aplavin](https://discourse.julialang.org/u/aplavin)\
**Post date:** [February 14, 2023, 8:12am UTC](https://discourse.julialang.org/t/consecutive-findmin-and-findmax/94419/7 "2023-02-14T08:12:13Z")

</div>

> [@filchristou](#):
>
> I wish there was a `by` argument in the `findmin` function

`findmin(x -> (x.a, -x.b, x.c), mys)`
