如何在Julia中根据条件选择数组的子集

5

如何根据条件简单地选择数组的子集?我知道Julia不使用向量化,但必须有一种简单的方法可以做到以下操作,而不需要丑陋的多行for循环。

julia> map([1,2,3,4]) do x
       return (x%2==0)?x:nothing
       end
4-element Array{Any,1}:
  nothing
 2
  nothing
 4

期望的输出:

[2, 4]

观察到的输出:
[nothing, 2, nothing, 4]

7
你所说的“julia不使用向量化”是什么意思?这是不正确的。有时候没有使用向量化可以获得最快的性能,但你需要决定哪个对你更重要:性能还是代码简洁。 - tholy
1
+1 @tholy 的观点。向量化提高了可读性,但有时会导致性能不佳。我记得曾经回答过一个关于 find 性能的 相关问题。根据您的设计考虑,您可以编写自己的有效程序来处理 x % 2 == 0,或者只需使用 Julia 的易于阅读的 filterfind 函数,就像下面的人们所描述的那样。 - Kevin L. Keys
我所说的“向量化”更多地是从语法角度而不是优化角度来看。虽然@daycaster指出我实际上可以像Matlab一样索引数组,但我没有意识到,我只尝试过==以这种方式进行索引,而不是.==。我不确定该选择哪个答案,它们在不同方面都是正确的,并且非常有用。 - David Parks
4个回答

14

9

有逐元素运算符(以“.”开头):

julia> [1,2,3,4] % 2 .== 0
4-element BitArray{1}:
 false
  true
 false
  true

julia> x = [1,2,3,4]
4-element Array{Int64,1}:
 1
 2
 3
 4

julia> x % 2 .== 0
4-element BitArray{1}:
 false
  true
 false
  true

julia> x[x % 2 .== 0]
2-element Array{Int64,1}:
 2
 4

julia> x .% 2
4-element Array{Int64,1}:
 1
 0
 1
 0

8
你可以使用find()函数(或.==语法)来实现这一点。例如:
julia> x = collect(1:4)
4-element Array{Int64,1}:
 1
 2
 3
 4    

julia> y = x[find(x%2.==0)]
2-element Array{Int64,1}:
 2
 4

julia> y = x[x%2.==0]  ## more concise and slightly quicker
2-element Array{Int64,1}:
 2
 4

请注意,对于逐元素操作,使用.==语法。此外,请注意find()返回与条件匹配的索引。在这种情况下,与条件匹配的索引与数组元素匹配。但是,对于更一般的情况,我们要将find()函数放在括号中,以表示我们正在使用它从原始数组x中选择索引。更新:很好的指出了@Lutfullah Tomak关于filter()函数的观点。我认为find()可能更快,更节省内存。(尽管我知道匿名函数在0.5版本中可能会变得更好,所以这可能会改变?)至少在我的试验中,我得到了:
x = collect(1:100000000);
@time y1 = filter(x->x%2==0,x);  
# 9.526485 seconds (100.00 M allocations: 1.554 GB, 2.76% gc time)    

@time y2 = x[find(x%2.==0)]; 
# 3.187476 seconds (48.85 k allocations: 1.504 GB, 4.89% gc time)

@time y3 = x[x%2.==0];
# 2.570451 seconds (57.98 k allocations: 1.131 GB, 4.17% gc time)    

更新2:评论区提出很好的观点,x[x%2.==0]x[find(x%2.==0)]更快。


1
为什么不直接使用 x[x%2.==0] 呢?这里的 find 是不必要且缓慢的。 - 张实唯
在Julia 0.5中,我计时了一下,发现过滤器是最快的,但第三个可能存在问题,因为它需要很长时间来编译。 - Lutfullah Tomak
1
匿名函数在v0.5中将与普通函数一样快。相关的github问题页面在这里。因此,在v0.5+中,filter几乎肯定是正确的选择。 - Colin T Bowers
好的,知道了!v0.5的预计发布时间是什么时候? - Michael Ohlrogge
@aireties - @time y2 … 之所以更快,是因为它没有执行你认为它正在执行的操作。y2 是空的!你漏掉了 .== 中的 .。修复这个问题,你会发现调用 find() 的确更慢。 - mbauman
1
@MattB。你是对的!谢谢!我现在已经改了。 - Michael Ohlrogge

0

另一个更新版本:

v[v .% 2 .== 0]

可能,对于Julia的新版本,需要在%==之前添加广播点。


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