Search code examples
arraysjuliaequality

Check if all the elements of a Julia array are equal


The shortest way I can think of to test whether all the elements in an array arr are equal is all(arr[1] .== arr). While this is certainly short, it seems a bit inelegant. Is there a built-in function that does this?

I suspect there's something along the lines of ==(arr...), but that doesn't work because the == operator can only take two arguments. I'm not sure how Julia parses expressions like arr[1] == arr[2] == arr[3], but is there some way to adapt this to an array with an arbitrary number of elements?


Solution

  • Great question @tparker and great answer @ColinTBowers. While trying to think about them both, it occurred to me to try the straight-forward old-school Julian way-of-the-for-loop. The result was faster on the important input of a long vector of identical elements, so I'm adding this note. Also, the function name allequal seems to be appropriate enough to mention. So here are the variants:

    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
    

    And the benchmark:

    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)
    

    UPDATE: Another important case to benchmark is when there is a short-circuit opportunity. So (as requested in commment):

    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)
    

    All things being equal, a for version should get to be allequal in Base.