Is there a “minmax” that can have a `lt`

keyword like what `sort`

does? For example, some method that does the following:

```
minmax(x, y; lt=isless) = lt(x,y) ? (x,y) : (y,x)
```

Is there a “minmax” that can have a `lt`

keyword like what `sort`

does? For example, some method that does the following:

```
minmax(x, y; lt=isless) = lt(x,y) ? (x,y) : (y,x)
```

Can you give a small example in running code, or if not possible, an example with small input and the expected output.

I’ve updated the op

`min, max = sort([x, y], lt=...)`

I don’t think there is function like that. It seems strange to ask for it though. For example, if you wish to switch the order (`lt=(x, y) -> x ≥ y`

), why not simply do `max, min = minmax(x, y)`

?

1 Like

```
ifelse(lt(x,y), (x,y), (y,x))
```

is very simple and fast.

I would not call this `minmax`

, it has different semantics.

But defining and using any function in Julia like this is totally fine.

But note, the returning type is a Tuple which type depends on the arguments. So this function is not type stable since the return type would depend on the value of the numbers.

```
julia> function my_function(x, y; lt=isless)
return lt(x,y) ? (x,y) : (y,x)
end
my_function (generic function with 2 methods)
julia> @code_warntype my_function(1, 1.0)
MethodInstance for my_function(::Int64, ::Float64)
from my_function(x, y; lt) @ Main REPL[12]:1
Arguments
#self#::Core.Const(my_function)
x::Int64
y::Float64
Body::Union{Tuple{Float64, Int64}, Tuple{Int64, Float64}}
1 ─ %1 = Main.:(var"#my_function#3")(Main.isless, #self#, x, y)::Union{Tuple{Float64, Int64}, Tuple{Int64, Float64}}
└── return %1
```

More safe would be to restrict the function arguments to have the same type, or do type promotion to the same type.

```
julia> function my_function2(x::T, y::T; lt=isless) where T
return lt(x,y) ? (x,y) : (y,x)
end
my_function2 (generic function with 1 method)
julia> my_function2(1, 1.0)
ERROR: MethodError: no method matching my_function2(::Int64, ::Float64)
Closest candidates are:
my_function2(::T, ::T; lt) where T
@ Main REPL[16]:1
Stacktrace:
[1] top-level scope
@ REPL[17]:1
julia> my_function2(1, 1)
(1, 1)
julia> @code_warntype my_function2(1, 1)
MethodInstance for my_function2(::Int64, ::Int64)
from my_function2(x::T, y::T; lt) where T @ Main REPL[16]:1
Static Parameters
T = Int64
Arguments
#self#::Core.Const(my_function2)
x::Int64
y::Int64
Body::Tuple{Int64, Int64}
1 ─ %1 = Main.:(var"#my_function2#5")(Main.isless, #self#, x, y)::Tuple{Int64, Int64}
└── return %1
```

1 Like

It seems like this is maybe looking for something a tad more generic like “sort a short tuple.”

I found this snippet I had lying around. The syntax here is a tad unusual due to outsourcing the ordering to my `makeorder`

function, but something like the following might fit your bill (I leave it as an exercise to the reader to write the length=2 version). You can refactor the `makeorder`

component to expose the sorting keywords directly within `sorttup`

.

```
makeorder(;lt=isless,by=identity,rev::Union{Bool,Nothing}=nothing,order::Base.Order.Ordering=Base.Order.Forward,) = Base.Order.ord(lt,by,rev,order)
function sorttup((a,b,c)::NTuple{3},ordr=makeorder())
# sort 3 values
a,b = ifelse(Base.lt(ordr,b,a),(b,a),(a,b))
b,c = ifelse(Base.lt(ordr,c,b),(c,b),(b,c))
a,b = ifelse(Base.lt(ordr,b,a),(b,a),(a,b))
return a,b,c
end
function sorttup((a,b,c,d)::NTuple{4},ordr=makeorder())
# sort 4 values
a,b = ifelse(Base.lt(ordr,b,a),(b,a),(a,b))
c,d = ifelse(Base.lt(ordr,d,c),(d,c),(c,d))
a,c = ifelse(Base.lt(ordr,c,a),(c,a),(a,c))
b,d = ifelse(Base.lt(ordr,d,b),(d,b),(b,d))
b,c = ifelse(Base.lt(ordr,c,b),(c,b),(b,c))
return a,b,c,d
end
```

1 Like

TupleTools.jl is slower than SortingNetworks.jl but the latter doesn’t support `lt`

or `by`

. It’s exactly the motivation of this post though.

You apply this function to some big data?

Can you share an example for it?

Not too big, but kind of low-level. I need to sort intervals before calculating the union of them.

Other answers are good; I just want to point out that you may also be interested in

```
extrema(f, (x,y))
```

which always uses `<`

for comparisons, but allows you to preprocess the input with the function `f`

. (Plus it extends nicely to longer collections.) In the trivial case, it compiles down to exactly the same code as other solutions.

Also note that most answers use the tuple `(x, y)`

instead of the vector `[x, y]`

because the vector would allocate, whereas the tuple will not.

3 Likes