# Implement iterator over subsets of array

**URL:** https://discourse.julialang.org/t/implement-iterator-over-subsets-of-array/58251
**Category:** General Usage
**Created:** [March 30, 2021, 5:08pm UTC](https://discourse.julialang.org/t/implement-iterator-over-subsets-of-array/58251 "2021-03-30T17:08:07Z")
**Posts on this page:** 10
**Page:** 1

<div class="post-metadata">

### Author: ![lmiq](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/lmiq/32/18314_2.png) [@lmiq](https://discourse.julialang.org/u/lmiq)
#### Post date: [March 30, 2021, 5:08pm UTC](https://discourse.julialang.org/t/implement-iterator-over-subsets-of-array/58251/1 "2021-03-30T17:08:07Z")

</div>

Suppose I have an array like

```julia
x = [1, 1, 1, 2, 2, 3, 3, 3, 4, 4, 4, 4]

```

I want to loop over the sets of sequences of common numbers, using a syntax like:

```julia
for set in eachset(x)
   ...
end

```

Where `eachset(x)` should behave as an array of sets.

If I define

```julia
eachset(x) = [findall(isequal(i),x) for i in unique(x)]

```

I get the indexes of the elements of each set and I could use that (although I only need the ranges really).

But I understand that I do not need to really allocate that array to iterate over its elements. What do I have to implement to get an iterator instead of an array?

---

<div class="post-metadata">

### Author: ![Skoffer](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/skoffer/32/378_2.png) [@Skoffer](https://discourse.julialang.org/u/Skoffer)
#### Post date: [March 30, 2021, 5:22pm UTC](https://discourse.julialang.org/t/implement-iterator-over-subsets-of-array/58251/2 "2021-03-30T17:22:48Z")

</div>

`x` is always sorted in proper order? If yes, then you only need to implement `iterate`. It is very simple, consider this tutorial for example: [Writing Iterators in Julia 0.7](https://julialang.org/blog/2018/07/iterators-in-julia-0.7/)

---

<div class="post-metadata">

### Author: ![lmiq](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/lmiq/32/18314_2.png) [@lmiq](https://discourse.julialang.org/u/lmiq)
#### Post date: [March 30, 2021, 5:27pm UTC](https://discourse.julialang.org/t/implement-iterator-over-subsets-of-array/58251/3 "2021-03-30T17:27:11Z")

</div>

> [@Skoffer](#):
>
> `x` is always sorted in proper order?

It is. It is slightly more complicated than that, because the vector is not simply a vector of numbers, but a vector of structures which contain the counter, but the sets are sequential in the original vectors.

Thanks for the link. If anything changed from 0.7 please let me know.

---

<div class="post-metadata">

### Author: ![Skoffer](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/skoffer/32/378_2.png) [@Skoffer](https://discourse.julialang.org/u/Skoffer)
#### Post date: [March 30, 2021, 5:29pm UTC](https://discourse.julialang.org/t/implement-iterator-over-subsets-of-array/58251/4 "2021-03-30T17:29:25Z")

</div>

Not any changes that I know of. It works the same on 1.7, at least my last Iterator did.

---

<div class="post-metadata">

### Author: ![Skoffer](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/skoffer/32/378_2.png) [@Skoffer](https://discourse.julialang.org/u/Skoffer)
#### Post date: [March 30, 2021, 5:32pm UTC](https://discourse.julialang.org/t/implement-iterator-over-subsets-of-array/58251/5 "2021-03-30T17:32:37Z")

</div>

Since the topic was named `implement` I forget that there are other options (like use). Maybe this one will useful: [Introduction · IterTools](https://juliacollections.github.io/IterTools.jl/latest/#groupby(f,-xs)-1)

---

<div class="post-metadata">

### Author: ![sijo](https://avatars.discourse-cdn.com/v4/letter/s/da6949/32.png) [@sijo](https://discourse.julialang.org/u/sijo)
#### Post date: [March 30, 2021, 5:57pm UTC](https://discourse.julialang.org/t/implement-iterator-over-subsets-of-array/58251/6 "2021-03-30T17:57:53Z")

</div>

You can use a generator instead of array comprehension to avoid allocating the main array:

```julia
( findall(isequal(i),x) for i in unique(x) )

```

instead of

```julia
[findall(isequal(i),x) for i in unique(x)]

```

but that’s still quite inefficient compared to a hand-crafted iterator…

---

<div class="post-metadata">

### Author: ![lmiq](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/lmiq/32/18314_2.png) [@lmiq](https://discourse.julialang.org/u/lmiq)
#### Post date: [March 30, 2021, 6:11pm UTC](https://discourse.julialang.org/t/implement-iterator-over-subsets-of-array/58251/7 "2021-03-30T18:11:51Z")

</div>

Maybe if I provide some more information on the problem it gets clearer:

I have a `struct` named `Atom`, which contains the information of the atoms of my system. To simplify, let us suppose that it has 2 fields, the `name` and the molecule to which it belongs, i. e.:

```julia
struct Atom
  name::String
  molecule::Int
end

```

Now I have a vector of “atoms”, for example with 2 water molecules:

```julia
julia> atoms = [ Atom("O",1), Atom("H",1), Atom("H",1), 
                 Atom("O",2), Atom("H",2), Atom("H",2) ]
6-element Vector{Atom}:
 Atom("O", 1)
 Atom("H", 1)
 Atom("H", 1)
 Atom("O", 2)
 Atom("H", 2)
 Atom("H", 2)

```

The molecules are always consecutive (not necessarily consecutive, but the molecule numbers are unique for each molecule), and are numbered according to the `molecule` field. What I want is to iterate over the molecules, with:

```julia
for molecule in eachmolecule(atoms)
    ...
end

```

So I have to implement the `eachmolecule` function that generates the iterator.

One thing that I have to decide what is one molecule. It may be a vector of atoms, a view of a vector of atoms, or another struct with the range of atoms of the original vector of atoms (the option I am leaning to).

Working on it from the information provided. Thanks!

---

<div class="post-metadata">

### Author: ![Henrique\_Becker](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/henrique_becker/32/15443_2.png) [@Henrique\_Becker](https://discourse.julialang.org/u/Henrique_Becker)
#### Post date: [March 30, 2021, 6:29pm UTC](https://discourse.julialang.org/t/implement-iterator-over-subsets-of-array/58251/8 "2021-03-30T18:29:40Z")

</div>

> [@lmiq](#):
>
> One thing that I have to decide is what is one molecule. It may be a vector of atoms, a view of a vector of atoms, or another struct with the range of atoms of the original vector of atoms (the option I am leaning to).

If you wanna follow the example of `Iterators.partition` it uses `SubArray`.

```julia
help?> Iterators.partition
  partition(collection, n)

  Iterate over a collection n elements at a time.

  Examples
  ≡≡≡≡≡≡≡≡≡≡

  julia> collect(Iterators.partition([1,2,3,4,5], 2))
  3-element Array{SubArray{Int64,1,Array{Int64,1},Tuple{UnitRange{Int64}},true},1}:
   [1, 2]
   [3, 4]
   [5]

```

I think following the trail given by `@edit Iterators.partition([1, 2, 3, 4], 2)` may give you an example of how to implement the iterator you want, as `Iterators.partition` (or better, the `iterate` for `PartitionIterator`) is probably the code in `Base` that most closely resembles what you want.

---

<div class="post-metadata">

### Author: ![Skoffer](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/skoffer/32/378_2.png) [@Skoffer](https://discourse.julialang.org/u/Skoffer)
#### Post date: [March 30, 2021, 7:28pm UTC](https://discourse.julialang.org/t/implement-iterator-over-subsets-of-array/58251/9 "2021-03-30T19:28:45Z")

</div>

How about something like this

```julia
struct Atom
  name::String
  molecule::Int
end

atoms = [ Atom("O",1), Atom("H",1), Atom("H",1), 
                 Atom("O",2), Atom("H",2), Atom("H",2) ]

struct EachMolecule 
    atoms::Vector{Atom}
end

eachmolecule(atoms) = EachMolecule(atoms)

function Base.iterate(em::EachMolecule, state = 1)
    r0 = state
    r0 > length(em.atoms) && return nothing
    m0 = em.atoms[r0].molecule
    r1 = r0
    while r1 <= length(em.atoms)
        em.atoms[r1].molecule != m0 && return (r0:r1 - 1, r1)
        r1 += 1
    end

    return (r0:r1 - 1, r1)
end

```

```julia
julia> for molecule in eachmolecule(atoms)
           println(molecule)
       end
1:3
4:6

```

---

<div class="post-metadata">

### Author: ![lmiq](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/lmiq/32/18314_2.png) [@lmiq](https://discourse.julialang.org/u/lmiq)
#### Post date: [March 30, 2021, 7:59pm UTC](https://discourse.julialang.org/t/implement-iterator-over-subsets-of-array/58251/10 "2021-03-30T19:59:16Z")

</div>

> [@Skoffer](#):
>
> ```julia
> eachmolecule(atoms) = EachMolecule(atoms)
> 
> ```

That was the part over which I was beating my brains out 🙂

This is the second _large_ contribution you give to that package in terms of how things are done! I promise that when it becomes something useful you will be justly acknowledged. Thank you very much!
