fellow julia(ns) :)
I am having trouble figuring out the most efficient way to pick a tuple based on a minimum value requirement for a vector of tuples, example below should help make sense
A = [(10,1), (34,2), (5,3)]
For the above vector of tuples, I would like to select the tuple whose first element is the smallest among all the first elements of tuples inside the array, for the case above it should be
(5,3)
I have been on this for hours but still can not figure out a way to do this without loops + dummy variables?
Any help is appreciated :D
Also if your tuples consist of objects that support comparisons on all dimensions (not only the first one) or you know that the first dimension is unique (so that the next dimensions are never used in comparison) then you can also do just:
julia> argmin(A)
3
julia> minimum(A)
(5, 3)
as for tuples argmin
and minimum
use lexicographic comparisons by default.
This will fail in e.g. this case (you have a tie on a first dimension, and the second dimension does not support comparisons):
julia> argmin([(1,im), (1,im)])
ERROR: MethodError: no method matching isless(::Complex{Bool}, ::Complex{Bool})
but this works as fist dimension has no ties:
julia> argmin([(2,im), (1,im)])
2
Also note that this might differ in case of ties with the solution given by @mcabbott in cases when you have ties in the minimum value:
julia> A = [(1,2), (1,1)]
2-element Array{Tuple{Int64,Int64},1}:
(1, 2)
(1, 1)
julia> argmin(first.(A))
1
julia> argmin(A)
2
as using first.
will return the first occurrence of minimum value over the first dimension and not using first.
will return the first occurrence of minimum value over all dimensions.
But if your problem satisfies the conditions I gave here (which is likely in practice) then my solution will be faster as it is non-allocating.
Finally, if you want a solution that is non-allocating and works the same way as @mcabbott proposal use reduce
like this:
julia> A = [(10,1), (34,2), (5,3)]
3-element Array{Tuple{Int64,Int64},1}:
(10, 1)
(34, 2)
(5, 3)
julia> reduce((x,y) -> y[2][1] < x[2][1] ? y : x, enumerate(A))
(3, (5, 3))
julia> A = [(1,im), (1,im)]
2-element Array{Tuple{Int64,Complex{Bool}},1}:
(1, im)
(1, im)
julia> reduce((x,y) -> y[2][1] < x[2][1] ? y : x, enumerate(A))
(1, (1, im))
julia> A = [(1,2), (1,1)]
2-element Array{Tuple{Int64,Int64},1}:
(1, 2)
(1, 1)
julia> reduce((x,y) -> y[2][1] < x[2][1] ? y : x, enumerate(A))
(1, (1, 2))
Unfortunately findmin
doesn't take a function to tell it what to look at, the way sort
does. But you can find the index by first separating first.(B)
and then calling argmin
:
julia> B = [(10,1), (77,7), (34,2), (5,3)];
julia> sort(B, by=first)[1]
(5, 3)
julia> B[argmin(first.(B))]
(5, 3)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With