各位朋友们,Julia(ns) :)
我在尝试找出一种能够基于向量中元组的最小值要求来选择元组的最高效方法,下面的例子将有助于理解:
A = [(10,1), (34,2), (5,3)]
对于上面的元组向量,我想选择第一个元素是所有数组内元组的第一个元素中最小的元组,对于上面的情况应该是
(5,3)
我已经花了几个小时但仍然无法找到一种不使用循环+虚拟变量来完成这个问题的方法?
非常感谢任何帮助 :D
julia> argmin(A)
3
julia> minimum(A)
(5, 3)
关于元组,argmin
和minimum
默认使用按字典顺序比较。
在某些情况下会失败,例如在第一维上有平局,而第二维不支持比较的情况:
julia> argmin([(1,im), (1,im)])
ERROR: MethodError: no method matching isless(::Complex{Bool}, ::Complex{Bool})
但是这是有效的,因为第一维没有任何并列的情况:
julia> argmin([(2,im), (1,im)])
2
请注意,在最小值出现 Tie 的情况下,此解决方案可能与 @mcabbott 给出的解决方案不同:
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
使用 first.
会返回第一维度上最小值的第一次出现,而不使用 first.
则会返回所有维度上最小值的第一次出现。
但是,如果你的问题符合我在这里给出的条件(实际上很可能如此),那么我的解决方案将更快,因为它不需要分配内存。
最后,如果您想要一个与 @mcabbott 的建议相同且不需要分配内存的解决方案,请使用以下方式进行 reduce
:
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))
不幸的是,findmin
不接受函数来告诉它应该查找什么,就像 sort
一样。但是你可以通过先分离 first.(B)
然后调用 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)
reduce
很聪明,但是有点啰嗦。如果能够内置为by=first
或其他形式就好了。(我最初误读问题,以为要按最后一个条目排序。) - mcabbott