Julia函数:从元组数组中选择一个元组

4

各位朋友们,Julia(ns) :)

我在尝试找出一种能够基于向量中元组的最小值要求来选择元组的最高效方法,下面的例子将有助于理解:

A = [(10,1), (34,2), (5,3)]

对于上面的元组向量,我想选择第一个元素是所有数组内元组的第一个元素中最小的元组,对于上面的情况应该是

(5,3)

我已经花了几个小时但仍然无法找到一种不使用循环+虚拟变量来完成这个问题的方法?

非常感谢任何帮助 :D

2个回答

4
此外,如果你的元组中的对象支持所有维度的比较(不仅是第一维),或者你知道第一维是唯一的(所以下一个维度永远不会用于比较),那么你也可以这样做:
julia> argmin(A)
3

julia> minimum(A)
(5, 3)

关于元组,argminminimum默认使用按字典顺序比较。

在某些情况下会失败,例如在第一维上有平局,而第二维不支持比较的情况:

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

1

不幸的是,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)

这种方法的问题在于对于大型数据集来说,会浪费很多内存。 - xiaodai
当然。上面的reduce很聪明,但是有点啰嗦。如果能够内置为by=first或其他形式就好了。(我最初误读问题,以为要按最后一个条目排序。) - mcabbott

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接