# Consecutive findmin and findmax

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`

``````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

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

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

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

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

Dunno if this qualifies as elegant, but …

``````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)
``````
1 Like
``````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
``````
1 Like

Another method:

``````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)
``````
6 Likes

Check also this option:

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

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.

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

3 Likes