检查Julia数组的所有元素是否相等

时间:2017-11-30 02:13:46

标签: arrays julia equality

我能想到的测试数组arr中所有元素是否相等的最短路径是all(arr[1] .== arr)。虽然这当然很短,但似乎有点不雅。是否有内置函数可以执行此操作?

我怀疑==(arr...)还有一些东西,但这不起作用,因为==运算符只能接受两个参数。我不确定Julia如何解析像arr[1] == arr[2] == arr[3]这样的表达式,但是有没有办法让它适应具有任意数量元素的数组?

3 个答案:

答案 0 :(得分:10)

all是正确的解决方案,但您希望方法all(p, itr)用于谓词p和可迭代itr,因为它会采用短路行为(尽快中断)找到false。所以:

all(y->y==x[1], x)

要查看差异,您可以运行以下小速度测试:

for n = 100000:250000:1100000
    x = rand(1:2, n);
    @time all(x .== x[1]);
    @time all(y->y==x[1], x);
    println("------------------------")
end

忽略第一次迭代,因为它是时间编译时间。

  0.000177 seconds (22 allocations: 17.266 KiB)
  0.006155 seconds (976 allocations: 55.062 KiB)
------------------------
  0.000531 seconds (23 allocations: 47.719 KiB)
  0.000003 seconds (1 allocation: 16 bytes)
------------------------
  0.000872 seconds (23 allocations: 78.219 KiB)
  0.000001 seconds (1 allocation: 16 bytes)
------------------------
  0.001210 seconds (23 allocations: 108.781 KiB)
  0.000001 seconds (1 allocation: 16 bytes)
------------------------
  0.001538 seconds (23 allocations: 139.281 KiB)
  0.000002 seconds (1 allocation: 16 bytes)

第一个解决方案显然是O(n),而第二个解决方案最好是O(1),最坏的是O(n)(取决于itr的数据生成过程。)

答案 1 :(得分:10)

很棒的问题@tparker和很棒的答案@ColinTBowers。在试图同时考虑它们时,我想到了尝试直接老派朱利安的方式 - for - 循环。结果在相同元素的长向量的重要输入上更快,所以我添加了这个注释。此外,函数名allequal似乎足以提及。所以这里有变种:

allequal_1(x) = all(y->y==x[1],x)

allequal_2(x) = foldl(==,x)   # another way but doesn't short-circuit :(

@inline function allequal_3(x)
    length(x) < 2 && return true
    e1 = x[1]
    i = 2
    @inbounds for i=2:length(x)
        x[i] == e1 || return false
    end
    return true
end

基准:

julia> using BenchmarkTools

julia> v = fill(1,10_000_000);  # long vector of 1s

julia> allequal_1(v)
true

julia> allequal_2(v)
true

julia> allequal_3(v)
true

julia> @btime allequal_1($v);
  9.573 ms (1 allocation: 16 bytes)

julia> @btime allequal_2($v);
  10.585 ms (0 allocations: 0 bytes)

julia> @btime allequal_3($v);
  6.853 ms (0 allocations: 0 bytes)

更新:基准测试的另一个重要案例是存在短路机会。所以(按照通知要求):

julia> v[100] = 2
2

julia> allequal_1(v),allequal_2(v),allequal_3(v)
(false, false, false)

julia> @btime allequal_1($v);
  108.946 ns (1 allocation: 16 bytes)

julia> @btime allequal_2($v);
  10.325 ms (0 allocations: 0 bytes)

julia> @btime allequal_3($v);
  68.221 ns (0 allocations: 0 bytes)

第二个版本allequal_2的表现非常糟糕,因为它不会短路。

在所有条件相同的情况下,for版本应该在Base中为allequal

答案 2 :(得分:6)

只是一个小改进:allsame(x) = all(y -> y == first(x), x)allsame(x) = all(y -> y == x[1], x)更通用,即使x不是AbstractArray,例如{发电机。