Iterator over upper triangular part of Cartesian product?

Is a (preferably efficient) implementation of the following available in some package?

triiter(x) = ((a[2], b) for a in enumerate(x) for b in Iterators.drop(x, a[1]))
julia> collect(triiter('a':'d'))
6-element Vector{Tuple{Char, Char}}:
 ('a', 'b')
 ('a', 'c')
 ('a', 'd')
 ('b', 'c')
 ('b', 'd')
 ('c', 'd')

How about Combinatorics.jl?

julia> using Combinatorics

julia> collect(combinations('a':'d', 2))
6-element Vector{Vector{Char}}:
 ['a', 'b']
 ['a', 'c']
 ['a', 'd']
 ['b', 'c']
 ['b', 'd']
 ['c', 'd']

That has the advantage of being in widely-used package. But, it’s not very performant

using Combinatorics

combiter(x) = combinations(x, 2)

triiter(x) = ((a[2], b) for a in enumerate(x) for b in Iterators.drop(x, a[1]))

isrelprime(x, y) = gcd(x, y) == 1
julia> @btime all(x -> isrelprime(x...), combiter((1,3,7,11)));
  508.378 ns (13 allocations: 864 bytes)

julia> @btime all(x -> isrelprime(x...), triiter((1,3,7,11)));
  58.625 ns (0 allocations: 0 bytes)
1 Like

I had posted

triiter(it) = ((a,b) for (n,b) in enumerate(it) for a in take(n, it))

then realized it’s basically the same as the OP. Oops :slight_smile:

2 Likes