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

tpa*_*ker 14 arrays equality julia

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

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

Col*_*ers 11

all是正确的解决方案,但您需要all(p, itr)谓词p和迭代的方法itr,因为它将采用短路行为(一旦false找到就中断).所以:

all(y->y==x[1], x)
Run Code Online (Sandbox Code Playgroud)

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

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

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

  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)
Run Code Online (Sandbox Code Playgroud)

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

  • @tparker`allsame(x)= all(y-> y == x [1],x)`.关于该语言的一个好处是,自己编写这些快捷方式并将它们放在自己的核心包中是多么容易.更一般地说,Julia社区强烈推动尽可能减少"Base".每种类型的操作都很好,简单,功能名称可以在包中,如果有足够的人喜欢它,包装就会变得流行,等等......但是`Base`仍然是精简和快速的. (2认同)

Dan*_*etz 11

很棒的问题@tparker和很棒的答案@ColinTBowers.在尝试两者兼顾的同时,我想到了尝试直接的老式朱利安式的for循环方式.结果在相同元素的长向量的重要输入上更快,所以我添加了这个注释.此外,功能名称allequal似乎足以提及.所以这里是变种:

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

# allequal_2(x) used to be erroneously defined as foldl(==,x)   

@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
Run Code Online (Sandbox Code Playgroud)

而基准:

julia> using BenchmarkTools

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

julia> allequal_1(v)
true

julia> allequal_3(v)
true

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

julia> @btime allequal_3($v);
  6.853 ms (0 allocations: 0 bytes)
Run Code Online (Sandbox Code Playgroud)

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

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_3($v);
  68.221 ns (0 allocations: 0 bytes)
Run Code Online (Sandbox Code Playgroud)

第二个版本for因为没有短路而表现糟糕.

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

  • 请注意,“allequal_2”的最优性不是重点,因为它是不正确的!例如,“allequal_2([0,0,0])”的计算结果为“false”。 (2认同)

Pab*_*ose 8

只是一个轻微的改进:allsame(x) = all(y -> y == first(x), x)比一般的更为通用allsame(x) = all(y -> y == x[1], x),甚至在x不是AbstractArray例如发电机的情况下工作.

  • 特别是,它适用于具有非标准索引的数组,例如从零开始。顺便说一句,如果没记错的话,你可以写 `==(first(x))` 而不是 `y -&gt; y == first(x)`。那个是新的。 (2认同)
  • 它是一个 Julia 对象,可以迭代生成值,而无需为它们分配容器或将它们写入内存。例如,像 `c = [x^2 for x in 1:100]` 这样的推导式分配了前 100 个整数的平方的向量。相比之下,生成器 `g = (x^2 for x in 1:100)` 按顺序生成相同的值,而不分配向量。你可以做类似`for s in g; $show s; end` 来打印它们。生成器被证明是一个非常强大的性能工具。 (2认同)