# Changing length of PSeq array on every repeat?

Say I have a pattern like `Pseq([1,2,3,4], inf)`. I’d like the number of elements in the sequence to vary on each repeat, according to another pattern. On the first playthrough I want to play all 4 elements, then 3, 2, back up to 3, and then 4 again, and so on. How can I achieve this?

For example, I’ve been trying this:

``````(
p = Pbind(
\degree, Pn(Pfin(Pseq([1,2,3,4]), Pseq([1, 2, 3, 4, 5, 6, 7])), inf),
\dur, Pseq([0.4], inf),
\sustain, 0.15
).play
)
``````

But on each repeat the pattern just plays the first 4 notes, or whatever number of elements happen to be in the array of the first sequence.

``````Pn(Pser((1..7), { rrand(2, 7) }), inf)

// or
Pn(Pser((1..7), Pwhite(2, 7, inf).asStream), inf)
``````

Note that a pattern used as a number of repeats normally needs to have `.asStream` attached.

hjh

1 Like

Ah, the `.asStream` seems to be what I was missing.

This works for me:

``````(
p = Pbind(
\degree, Pn(Pser((1..7), Pseq((7..2) ++ (2..7)).asStream), inf),
\dur, Pseq([0.4], inf),
\sustain, 0.15
).play
)
``````

More generally speaking, the `repeats` argument is usually evaluated with `.value` in the Patterns from classlib. That makes it possible to use “naked” functions for `repeats` but also streams/routines because `.value` for streams/routines is the same as `.next`. However `.value` for Patterns just returns the pattern.

``````r = r { 42.yield }; [r.value, r.value] // -> [ 42, nil ]
Pbind().value // -> a Pbind
``````

Also `.iter` is a good shortcut synonym for `.asStream` on Patterns, but it can be a gotcha if you call it on an array if you didn’t intend to iterate over the array’s items but use it as a constant.

``````[1, 2].iter.next // -> 1
[1, 2].asStream.next // -> [ 1, 2 ]
``````

``````Pn(Pser((1..7), Pseq((7..2) ++ (2..7)).asStream), inf)
``````

can be just

``````Pn(Pser((1..7), ((7..2) ++ (2..7)).iter))
``````

(`inf` is the default repeats for Pn, so that’s redundant too.)

Also there are already defined methods for mirroring arrays

``````(7..2) ++ (2..7) == (7..2).mirror2
``````

And the array `pyramid` methods can “directly” generate the same number patterns you want (in finite form of course), although it’s hard to remember the right invocations; their argument is an algorithm number!

``````n = 4 // use 7 for your original ex.; this is for shorter output
a = (n..2).mirror2
g = Pn(Pseries(1, 1, a.iter), a.size).iter.all // or
h = (1..n).pyramidg(3).drop(-1).mirror2.flatten
g == h // test

// pyramid(7) almost does what you want by itself
// but you have to remove the middle element
k = (1..n).pyramid(7); k.removeAt(k.size div: 2); k
k == g
``````

There are also list comprehensions (actually generators as they return routines) in SC… which make some of that pyramid business more comprehensible …

``````(1..n).pyramidg(3).drop(-1)
// same as
{: (1..x), x <- (n..2) }.all

{: (1..x), x <- (n..2).mirror2 }.all.flatten
// same as
(1..n).pyramidg(3).drop(-1).mirror2.flatten
``````

And a rather obscure/undocumented way of doing the same without flatten

``````{{; (1..x) do: _.yield, x <- (n..2).mirror2 }}.r.all
``````

Also this is a “flatMap” application, but then so all the `pyramid` functions basically…

``````(n..2).mirror2.collect((1.._)).flatten
``````

As a variation on that, “auto-flattening” can be done by producing a Pseq that has an array of Pseqs as its argument.

``````Pseq((n..2).mirror2.collect{|x| Pseq((1..x))}).iter.all
``````

In that last expression, using `Pseries(1, 1, x)` probably marginally more efficient than `Pseq((1..x))` for longish things. On that angle though, the `Pn(Pseries` solution is even more efficient though; properly encapsulating the `a` variable looks something like

``````Plazy{var a = (n..2).mirror2; Pn(Pseries(1, 1, a.iter), a.size)}.iter.all
``````

You can avoid generating/storing the array `a` too, although that looks pretty long to write as a constant-storage Pattern:

``````(
Plazy{
var itr = (Pseries(n, -1, n-1) ++ Pseries(2, 1, n-1)).iter;
Pn(Pseries(1, 1, itr), 2*n-2)
}.iter.all
)
``````

Premature optimization As it turns out, SC list comprehensions automatically detect and apply this kind of optimization.

Trying to do something similar here, but noticing that this bit of code crashes my server when it reaches the end of the sequence. Same when substituting:

``````Pn(Pser((1..7), ((7..2) ++ (2..7)).iter))
``````

Can anyone confirm this and/or suggest an alternate route?