Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

julia function to pick a tuple from an array of tuples

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

like image 222
ppatel26 Avatar asked Oct 18 '25 15:10

ppatel26


2 Answers

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))
like image 128
Bogumił Kamiński Avatar answered Oct 21 '25 04:10

Bogumił Kamiński


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)
like image 41
mcabbott Avatar answered Oct 21 '25 04:10

mcabbott