# Solving this without a loop (learning purposes)

**URL:** <https://discourse.julialang.org/t/solving-this-without-a-loop-learning-purposes/103013>\
**Category:** Performance\
**Tags:** question, transducers, folds\
**Created:** [August 20, 2023, 7:45pm UTC](https://discourse.julialang.org/t/solving-this-without-a-loop-learning-purposes/103013 "2023-08-20T19:45:30Z")\
**Posts on this page:** 15\
**Page:** 1

<div class="post-metadata">

**Author:** ![CodeGodz](https://avatars.discourse-cdn.com/v4/letter/c/aeb1de/32.png) [@CodeGodz](https://discourse.julialang.org/u/CodeGodz)\
**Post date:** [August 20, 2023, 7:45pm UTC](https://discourse.julialang.org/t/solving-this-without-a-loop-learning-purposes/103013/1 "2023-08-20T19:45:30Z")

</div>

I’m trying to get more familiar with using `Transducers.jl` or related functions that avoid loops - just to learn. Let’s say I have this simple vector  
`x = Bool[1,1,0,0,1,1,0,1]`  
and I want to find the indices of adjacent True, so in this case, get:

```julia
(1,2)
(5,6)
(8,8)

```

I came this far:  
`collect(Enumerate(), x) |> Filter(x->x[2]==1) |> Map(x -> x[1]) |> collect`  
Which gives:

```julia
5-element Vector{Int64}:
 1
 2
 5
 6
 8

```

Then I should basically “loop” through these to get the adjacent values I thought of fold but that needs the same output format as the input. Would be curious to see how this can be solved without writing a loop 🙂

* * *

**EDIT**  
Maybe `findall` would be easier to get the indexes haha:  
`findall(x->x==true, z)`

```julia
5-element Vector{Int64}:
 1
 2
 5
 6
 8

```

But the latter step I’m not sure how to solve without a loop

---

<div class="post-metadata">

**Author:** ![oheil](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/oheil/32/220745_2.png) [@oheil](https://discourse.julialang.org/u/oheil)\
**Post date:** [August 20, 2023, 8:20pm UTC](https://discourse.julialang.org/t/solving-this-without-a-loop-learning-purposes/103013/2 "2023-08-20T20:20:21Z")

</div>

Somehow your examples don’t work and why do you want the index 8 ?

Here is my first approach:

```julia
julia> x = Bool[1,1,0,0,1,1,0,1]
8-element Vector{Bool}:
 1
 1
 0
 0
 1
 1
 0
 1

julia> findall( x .& append!(x[2:end],false) )
2-element Vector{Int64}:
 1
 5

```

And you should define what you mean with “without loops”. At the end there will be a loop executed.

---

<div class="post-metadata">

**Author:** ![CodeGodz](https://avatars.discourse-cdn.com/v4/letter/c/aeb1de/32.png) [@CodeGodz](https://discourse.julialang.org/u/CodeGodz)\
**Post date:** [August 20, 2023, 8:21pm UTC](https://discourse.julialang.org/t/solving-this-without-a-loop-learning-purposes/103013/3 "2023-08-20T20:21:49Z")

</div>

I want to get the indices of the `1`s or interval when multiple adjacent `1`s are present. Hence all intervals for ones would be `[[1,2], [5,6], [8,8] ]` the last one is not really an “interval” but there is no adjacent value.

Not sure what your code answers with `1, 5`?

---

<div class="post-metadata">

**Author:** ![oheil](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/oheil/32/220745_2.png) [@oheil](https://discourse.julialang.org/u/oheil)\
**Post date:** [August 20, 2023, 8:23pm UTC](https://discourse.julialang.org/t/solving-this-without-a-loop-learning-purposes/103013/4 "2023-08-20T20:23:49Z")

</div>

```julia
julia> findall( x .&& append!(x[2:end],true) )
3-element Vector{Int64}:
 1
 5
 8

```

I still don’t get the index 8.  
Would be trivial to generate the second index here, but with the 8 it’s a problem.

---

<div class="post-metadata">

**Author:** ![CodeGodz](https://avatars.discourse-cdn.com/v4/letter/c/aeb1de/32.png) [@CodeGodz](https://discourse.julialang.org/u/CodeGodz)\
**Post date:** [August 20, 2023, 8:25pm UTC](https://discourse.julialang.org/t/solving-this-without-a-loop-learning-purposes/103013/5 "2023-08-20T20:25:26Z")

</div>

Does this also only work for two adjacent values? I actually meant it to also work in the case of:

```julia
 1
 1
 1
 0
 1
 1
 0
 1

```

For example

---

<div class="post-metadata">

**Author:** ![oheil](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/oheil/32/220745_2.png) [@oheil](https://discourse.julialang.org/u/oheil)\
**Post date:** [August 20, 2023, 8:26pm UTC](https://discourse.julialang.org/t/solving-this-without-a-loop-learning-purposes/103013/6 "2023-08-20T20:26:47Z")

</div>

> [@CodeGodz](#):
>
> Does this also only work for two adjacent values?

True.  
Not a solution than.  
And now I understand the 8…

---

<div class="post-metadata">

**Author:** ![rafael.guerra](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/rafael.guerra/32/216610_2.png) [@rafael.guerra](https://discourse.julialang.org/u/rafael.guerra)\
**Post date:** [August 20, 2023, 9:02pm UTC](https://discourse.julialang.org/t/solving-this-without-a-loop-learning-purposes/103013/7 "2023-08-20T21:02:06Z")

</div>

One-shot:

```julia
tuple.(findall(diff([0; x]) .== 1), findall(diff([x; 0]) .== -1))

```

**PS:**  
Splitting it into two lines and using views, does allocate less:

```julia
d = diff([0; x; 0])
@views tuple.(findall(d[1:end-1] .== 1), findall(d[2:end] .== -1))

```

---

<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:** [August 20, 2023, 9:45pm UTC](https://discourse.julialang.org/t/solving-this-without-a-loop-learning-purposes/103013/8 "2023-08-20T21:45:50Z")

</div>

for

> [@CodeGodz](#):
>
> find the indices of adjacent True

do you mean this?

```julia
using IterTools
x = Bool[0,1,1,1,0,0,1,1,0,1]
twin=collect(partition(x,2,1))
p=findall(==((1,1)),twin)
tuple.(p,p.+1)

```

---

<div class="post-metadata">

**Author:** ![CodeGodz](https://avatars.discourse-cdn.com/v4/letter/c/aeb1de/32.png) [@CodeGodz](https://discourse.julialang.org/u/CodeGodz)\
**Post date:** [August 20, 2023, 9:52pm UTC](https://discourse.julialang.org/t/solving-this-without-a-loop-learning-purposes/103013/9 "2023-08-20T21:52:19Z")

</div>

That indeed solves that part of the question

```julia
3-element Vector{Tuple{Int64, Int64}}:
 (2, 3)
 (3, 4)
 (7, 8)

```

But I want to connect the (2,3) - (3,4) → (2,4) to find the “true” stretches basically like the other answer

---

<div class="post-metadata">

**Author:** ![CodeGodz](https://avatars.discourse-cdn.com/v4/letter/c/aeb1de/32.png) [@CodeGodz](https://discourse.julialang.org/u/CodeGodz)\
**Post date:** [August 20, 2023, 10:03pm UTC](https://discourse.julialang.org/t/solving-this-without-a-loop-learning-purposes/103013/10 "2023-08-20T22:03:51Z")

</div>

Found a way using Tranducers.jl, not entirely sure if this elegant 😂  
`collect(Enumerate(), x) |> PartitionBy(x -> x[2] == true) |> Filter(x -> x[1][2] == true) |> Map(x-> (x[argmin(x)][1], x[argmax(x)][1])) |> collect `

Not that bad with 49 allocs, but I guess pretty bad for readability lol

---

<div class="post-metadata">

**Author:** ![ericphanson](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/ericphanson/32/215186_2.png) [@ericphanson](https://discourse.julialang.org/u/ericphanson)\
**Post date:** [August 20, 2023, 10:27pm UTC](https://discourse.julialang.org/t/solving-this-without-a-loop-learning-purposes/103013/11 "2023-08-20T22:27:30Z")

</div>

This is kind of like a run-length encoding, so you could use [`rle`](https://juliastats.org/StatsBase.jl/stable/misc/#StatsBase.rle) from StatsBase:

```julia
julia> x = Bool[1,1,0,0,1,1,0,1];

julia> vals, lens = rle(x)
(Bool[1, 0, 1, 0, 1], [2, 2, 2, 1, 1])

julia> run_starts = cumsum(lens) .- lens .+ 1
5-element Vector{Int64}:
 1
 3
 5
 7
 8

julia> run_stops = cumsum(lens)
5-element Vector{Int64}:
 2
 4
 6
 7
 8

julia> inds = findall(vals)
3-element Vector{Int64}:
 1
 3
 5

julia> collect(zip(run_starts[inds], run_stops[inds]))
3-element Vector{Tuple{Int64, Int64}}:
 (1, 2)
 (5, 6)
 (8, 8)

```

(of course, all these solutions are just putting the loop somewhere else 🙂).

---

<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:** [August 20, 2023, 10:27pm UTC](https://discourse.julialang.org/t/solving-this-without-a-loop-learning-purposes/103013/12 "2023-08-20T22:27:49Z")

</div>

```julia
map(vt->range(first.(vt)...),extrema.(filter(v->v[1][2],collect(IterTools.groupby(e->last(e),enumerate(x))))))

```

```julia
map(vt->first.(vt),extrema.(Iterators.filter(v->v[1][2],IterTools.groupby(e->last(e),enumerate(x)))))

```

```julia
julia> @btime map(vt->first.(vt),extrema.(Iterators.filter(v->v[1][2],IterTools.groupby(e->last(e),enumerate(x)))))
  942.857 ns (29 allocations: 2.09 KiB)
3-element Vector{Tuple{Int64, Int64}}:
 (2, 4)
 (7, 8)
 (10, 10)

julia> @btime collect(Enumerate(), x) |> PartitionBy(x -> x[2] == true) |> Filter(x -> x[1][2] == true) |> Map(x-> (x[argmin(x)][1], x[argmax(x)][1])) |> collect
  1.440 μs (59 allocations: 2.91 KiB)
3-element Vector{Tuple{Int64, Int64}}:
 (2, 4)
 (7, 8)
 (10, 10)

```

```julia
using IterTools
fvt(x)=first.(x)
fvt.(extrema.(Iterators.filter(v->v[1][2],groupby(e->last(e),enumerate(x)))))

```

---

<div class="post-metadata">

**Author:** ![mrufsvold](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mrufsvold/32/31600_2.png) [@mrufsvold](https://discourse.julialang.org/u/mrufsvold)\
**Post date:** [August 21, 2023, 12:28am UTC](https://discourse.julialang.org/t/solving-this-without-a-loop-learning-purposes/103013/13 "2023-08-21T00:28:52Z")

</div>

> [@ericphanson](#):
>
> all these solutions are just putting the loop somewhere else

 ![](https://global.discourse-cdn.com/julialang/original/3X/9/1/91383537be28284c9eacacd19f19b0953aea8f93.jpeg)  
-Programming history

---

<div class="post-metadata">

**Author:** ![CodeGodz](https://avatars.discourse-cdn.com/v4/letter/c/aeb1de/32.png) [@CodeGodz](https://discourse.julialang.org/u/CodeGodz)\
**Post date:** [August 21, 2023, 12:33am UTC](https://discourse.julialang.org/t/solving-this-without-a-loop-learning-purposes/103013/14 "2023-08-21T00:33:31Z")

</div>

Quite helpful in many cases though, things like `findall`, `findfirst`, `map` etc are easy to read and make code more compact.

---

<div class="post-metadata">

**Author:** ![mrufsvold](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mrufsvold/32/31600_2.png) [@mrufsvold](https://discourse.julialang.org/u/mrufsvold)\
**Post date:** [August 21, 2023, 12:46am UTC](https://discourse.julialang.org/t/solving-this-without-a-loop-learning-purposes/103013/15 "2023-08-21T00:46:23Z")

</div>

Sorry if my joke wasn’t clear – the history of programming has been hiding GOTOs with loops and if-else because it adds clarity and brevity to the code. Functional programming hides loops and if-else to add further clarity and brevity.

This is almost always good!
