# Nice way to iterate through a triangular matrix

**URL:** <https://discourse.julialang.org/t/nice-way-to-iterate-through-a-triangular-matrix/101667>\
**Category:** General Usage\
**Tags:** suggestions\
**Created:** [July 16, 2023, 1:48am UTC](https://discourse.julialang.org/t/nice-way-to-iterate-through-a-triangular-matrix/101667 "2023-07-16T01:48:01Z")\
**Posts on this page:** 11\
**Page:** 1

<div class="post-metadata">

**Author:** ![RobertGregg](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/robertgregg/32/22105_2.png) [@RobertGregg](https://discourse.julialang.org/u/RobertGregg)\
**Post date:** [July 16, 2023, 1:48am UTC](https://discourse.julialang.org/t/nice-way-to-iterate-through-a-triangular-matrix/101667/1 "2023-07-16T01:48:01Z")

</div>

I often need to loop through the upper/lower triangular section of a matrix and usually end up doing something like:

```julia
A = reshape(1:25,5,5)

for j in axes(A,2)
    for i in axes(A,1)
        if i>j
            @show A[i,j]
        end
    end
end

```

This is _fine_ but can lead to code with way too many indents. You could get rid of the if statement, but its still very clunky and takes a second to figure out whats going on:

```julia
for j in axes(A,2)
    for i in j+1:size(A,1)
        @show A[i,j]
    end
end

```

I came up with simpler solution and wanted to share it. Basically Iterators does all the heavy lifting.

```julia
lowTriIter(ax1, ax2) = Iterators.filter(i -> first(i)>last(i),
                                        Iterators.product(ax1,ax2) )

lowTriIter(A::AbstractMatrix) = lowTriIter(axes(A)...)

```

Which leads to code that looks like this:

```julia
for (i,j) in lowTriIter(A)
    @show A[i,j]
end

```

It’s pretty versatile like you could change the comparison to include the diagonal and there’s no fussing around with adding one to indices. You could probably even get it to work with CartesianIndices if you wanted. Feel free to suggest improvements 😁

---

<div class="post-metadata">

**Author:** ![Dan](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/dan/32/42581_2.png) [@Dan](https://discourse.julialang.org/u/Dan)\
**Post date:** [July 16, 2023, 2:39am UTC](https://discourse.julialang.org/t/nice-way-to-iterate-through-a-triangular-matrix/101667/2 "2023-07-16T02:39:27Z")

</div>

Another way could be:

```julia
lowTriIter2(A::AbstractMatrix) = 
  Iterators.flatten(Iterators.map(j->(j,i), i+1:size(A,1)) for i=1:size(A,2))

```

```julia
julia> collect(lowTriIter2(A))
10-element Vector{Tuple{Int64, Int64}}:
 (2, 1)
 (3, 1)
 (4, 1)
 (5, 1)
 (3, 2)
 (4, 2)
 (5, 2)
 (4, 3)
 (5, 3)
 (5, 4)

```

This avoids looping over the skipped indices, and therefore might save a little time.

---

<div class="post-metadata">

**Author:** ![RobertGregg](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/robertgregg/32/22105_2.png) [@RobertGregg](https://discourse.julialang.org/u/RobertGregg)\
**Post date:** [July 16, 2023, 5:02am UTC](https://discourse.julialang.org/t/nice-way-to-iterate-through-a-triangular-matrix/101667/3 "2023-07-16T05:02:11Z")

</div>

Oh I don’t think I would have ever thought of making a generator of maps, interesting. I guess you could skip right to the generator as well:

```julia
lowTriIter3(A::AbstractMatrix) =
    ((i,j) for j in axes(A,2) for i in j+1:size(A,1))

```

I do like that these methods skip over the additional iterations but I do wish they avoided the `i+1:size(A,1)` bit. Also I made my version more complicated than it need to be. I think I was worried about `axes(A)` having more than two iterators, but it won’t because A is already a matrix:

```julia
lowTriIter(A::AbstractMatrix) = 
    Iterators.filter(i -> first(i)>last(i), Iterators.product(axes(A)...))

```

---

<div class="post-metadata">

**Author:** ![baggepinnen](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/baggepinnen/32/693_2.png) [@baggepinnen](https://discourse.julialang.org/u/baggepinnen)\
**Post date:** [July 16, 2023, 5:33am UTC](https://discourse.julialang.org/t/nice-way-to-iterate-through-a-triangular-matrix/101667/4 "2023-07-16T05:33:45Z")

</div>

> [@RobertGregg](#):
>
> This is _fine_ but can lead to code with way too many indents.

You know you can write both iterations on one line?

```julia
for j in axes(A,2), i in j+1:size(A,1)
    @show A[i,j]
end

```

---

<div class="post-metadata">

**Author:** ![rocco\_sprmnt21](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/rocco_sprmnt21/32/20127_2.png) [@rocco\_sprmnt21](https://discourse.julialang.org/u/rocco_sprmnt21)\
**Post date:** [July 16, 2023, 2:28pm UTC](https://discourse.julialang.org/t/nice-way-to-iterate-through-a-triangular-matrix/101667/5 "2023-07-16T14:28:15Z")

</div>

> [@Iterating over elements of upper triangular matrix, but cartesian indices are needed](https://discourse.julialang.org/t/iterating-over-elements-of-upper-triangular-matrix-but-cartesian-indices-are-needed/65498):
>
> Basically what I (think) I need is this function: [https://stackoverflow.com/questions/27086195/linear-index-upper-triangular-matrix](https://stackoverflow.com/questions/27086195/linear-index-upper-triangular-matrix) Of course I can just implement it, two lines of code. But that seems something that probably is needed quite frequently in matrix computations, so I am surprised I didn’t find it as a Base function. First I thought that most people would prefer constructing an iterator like (for a 3x3 matrix, for example): julia\> for c in Iterators.filter(c -\> c[1] \< c[2], Carte…

---

<div class="post-metadata">

**Author:** ![RobertGregg](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/robertgregg/32/22105_2.png) [@RobertGregg](https://discourse.julialang.org/u/RobertGregg)\
**Post date:** [July 16, 2023, 4:29pm UTC](https://discourse.julialang.org/t/nice-way-to-iterate-through-a-triangular-matrix/101667/6 "2023-07-16T16:29:16Z")

</div>

I did, but that’s a fair point! It’s wild how many ways you can accomplish the same task.

I think I liked my version because it abstracted away the need to think about indices. Like if I wanted to change this nested loop to iterate over the upper triangle it would take me a minute to figure out versus just flipping a less-than sign. I get that’s just a preference though 🙂

---

<div class="post-metadata">

**Author:** ![RobertGregg](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/robertgregg/32/22105_2.png) [@RobertGregg](https://discourse.julialang.org/u/RobertGregg)\
**Post date:** [July 16, 2023, 4:36pm UTC](https://discourse.julialang.org/t/nice-way-to-iterate-through-a-triangular-matrix/101667/7 "2023-07-16T16:36:15Z")

</div>

Ah i didn’t see this. Sorry for the repeated topics. That formula for the `ut2ci(idx)` function is both amazing and headache inducing 🤣

---

<div class="post-metadata">

**Author:** ![bertschi](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/bertschi/32/33462_2.png) [@bertschi](https://discourse.julialang.org/u/bertschi)\
**Post date:** [July 16, 2023, 6:54pm UTC](https://discourse.julialang.org/t/nice-way-to-iterate-through-a-triangular-matrix/101667/8 "2023-07-16T18:54:21Z")

</div>

Just some additional thoughts …

First, you could also use iterator comprehensions and the definition of your iterator looks just like your for loop:

```julia
lowertriag(A::AbstractMatrix) = ((i,j) for j in axes(A, 2) for i in axes(A, 1) if i > j)

for (i, j) in lowertriag(A)
    @show A[i, j]
end

```

Further, `flatmap`, i.e., `flatten ∘ map`, is a very powerful combinator and most other operations on iterables can be defined in terms of it:

```julia
mymap(f, xs) = Iterators.flatmap(x -> (f(x),), xs)
myfilter(pred, xs) = Iterators.flatmap(x -> if pred(x); (x,) else empty((x,)) end, xs)

```

In the functional programming jargon a la Haskell, `flatmap` is the _monadic bind_ whereas `map` is the way more general functor instance for lists.

---

<div class="post-metadata">

**Author:** ![mkitti](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mkitti/32/12459_2.png) [@mkitti](https://discourse.julialang.org/u/mkitti)\
**Post date:** [July 16, 2023, 7:10pm UTC](https://discourse.julialang.org/t/nice-way-to-iterate-through-a-triangular-matrix/101667/9 "2023-07-16T19:10:07Z")

</div>

```julia
julia> (A[ci] for ci in CartesianIndices(A) if first(ci.I) ≤ last(ci.I)) |> collect
15-element Vector{Int64}:
  1
  6
  7
 11
 12
 13
 16
 17
 18
 19
 21
 22
 23
 24
 25

julia> (A[ci] for ci in CartesianIndices(A) if first(ci.I) ≥ last(ci.I)) |> collect
15-element Vector{Int64}:
  1
  2
  3
  4
  5
  7
  8
  9
 10
 13
 14
 15
 19
 20
 25

```

---

<div class="post-metadata">

**Author:** ![RobertGregg](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/robertgregg/32/22105_2.png) [@RobertGregg](https://discourse.julialang.org/u/RobertGregg)\
**Post date:** [July 16, 2023, 9:42pm UTC](https://discourse.julialang.org/t/nice-way-to-iterate-through-a-triangular-matrix/101667/10 "2023-07-16T21:42:04Z")

</div>

Oh I did see that `Iterators.flatmap` was new to v1.9. It definitely looks useful but I’m not sure how I would apply it to this situation.

---

<div class="post-metadata">

**Author:** ![singularitti](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/singularitti/32/17678_2.png) [@singularitti](https://discourse.julialang.org/u/singularitti)\
**Post date:** [October 12, 2024, 5:32am UTC](https://discourse.julialang.org/t/nice-way-to-iterate-through-a-triangular-matrix/101667/11 "2024-10-12T05:32:38Z")

</div>

I’m not sure how this `i > j` comparison or `i = j + 1` works on non-monotonic increasing array indices like [StarWarsArrays](https://github.com/giordano/StarWarsArrays.jl)?
