Check two iterators for equality without collecting

question

#1

I am looking for simple syntax that would compare two iterators itr1, itr2 for elementwise equality without collecting, and break early if there is a difference. MWE:

julia> VERSION
v"0.6.0-rc1.0"

julia> all(1:3 .== [1,2,3])
true

julia> all(1:3 .== (i for i in 1:3)) # but I want this to be true
false

Note that I know how to implement it, I am looking for simple syntax, equivalent to

function itreq(itr1, itr2)
    for (i1,i2) in zip(itr1, itr2)
        i1 == i2 || return false
    end
    true
end

itreq(1:3, (i for i in 1:3))

EDIT: I realized I really want something equivalent to collect(itr1) == collect(itr2), but without collect. Ie different lengths should also return false, so all(... .== ...) is not good.

In case you are wondering, this is just out of curiosity, the code in question has no performance impact. I am validating that a list of Cartesian indexes are really contiguous and in the right order, with a function not unlike

function combined_size(indexes)
    siz = reduce(max, indexes)
    ran = CartesianRange(siz)
    # FIXME inelegant collect below
    @argcheck collect(indexes) == collect(ran) "Non-contiguous indexes."
    siz
end

#2

We should probably have methods for all and any that work like map, taking a predicate which takes as many arguments as you pass iterables. Could you open a feature request issue?


#3

I thought about it and I am not sure it is a good idea. Something like

all(f, itr...) = all(tup->f(tup...), zip(itr...))

would work, apart from the fact that it would conflict with all(f::Function, A::AbstractArray, region) when used with two iterables, however

all(==, 1:3, (i for i in 1:4))

would be true, which is not necessarily what I want. One would need to test for one sequence consumed earlier than the other, but mapreduce would just finish silently.


#4

Typically map etc error out if the sizes aren’t compatible, and so should an iteration version of mapreduce.


#5

How about defining:
iterequal(iter,iters...) = all(t->length(t)==length(iter),iters) && all(all(t->t==x[1],x[2]) for x in zip(iter,zip(iters...)))

which uses all which is short-circuiting on boolean predicates.

In this examples:
julia> iterequal(1:3,1:3) true

and
julia> iterequal(1:3,1:4) false


#6

Only zip ignores length differences, stopping as soon as the first argument stops, and there’s an open issue somewhere with a lot of support for changing that (including from me).


#7