Is there a name for an iterator that is like `product(a, a)` except only distinct-indexed elements are paired

I often want to iterator over a iterable in such a way that distinct-index elements are only paired once. This is useful for things like one round round-robin leagues

for i in 1:length(a)-1
 for j in i+1:length(a)
    ai = a[i]
    aj = a[j]
    # do something with ai and aj
  end
end

But I want something like

for (ai, aj) in StairsIterator(a)
  # do something with ai aj
end
2 Likes

I think IterTools.subsets will do what you’re looking for. Something like:

for (i,j) in IterTools.subsets(1:length(a), Val{2}())
    # do something
end

This essentially returns the indices of an upper triangular matrix.

8 Likes

Using Subsets is very elegant. I am glad I asked.

2 Likes

Based on @Alexander_Knudson’s solution for the indices, implementing your StairsIterator should be straightforward:

using IterTools
using Base.Cartesian

StairIterator(a) = (
    (@nextract 2 a d -> a[ids[d]]; @ntuple 2 a)
       for ids in IterTools.subsets(1:length(a), Val{2}())
)

a = rand(3)
println(a)

for (ai, aj) in StairIterator(a)
    println("ai = $ai\t aj = $aj")
end
1 Like