Pattern like Pswitch but that pulls all its sub-patterns

Hi there, I was wondering if there is a value Pattern class I’m not aware of, that behaves more or less like Pswitch1 (lets an “index” switch between a list of patterns), except that it keeps pulling the next value from each of them “before” the switch is evaluated (and not only when they’re the “active” pattern). Another way to say it would be a Pattern that lets a value be overridden by another.

The following two approaches produce the same result (which is not what I want in this case):

a = Pseq((1..4), 2); // [ 1, 2, 3, 4, 1, 2, 3, 4 ]
b = Pseq((11..18), 1); // [ 11, 12, 13, 14, 15, 16, 17, 18 ]

Pswitch1([a, b], Pseq([0,0,1], 8)).asStream.nextN(8)
// -> [ 1, 2, 11, 3, 4, 12, 1, 2 ]

Pif(Pseq([true,true,false], 8), a, b).asStream.nextN(8)
// -> [ 1, 2, 11, 3, 4, 12, 1, 2 ]

But what I actually want would be:

// -> [ 1, 2, 13, 4, 1, 16, 3, 4 ]

Thanks,
Glen.

1 Like

Nothing out of the box which comes to my mind. If your basic data is Patterns you can use Ptuple for compounding:

x = Ptuple([a, b], inf);
i = Pseq([0, 0, 1], inf).iter;

x.collect { |y| y[i.next] }.iter.nextN(20);

You can also flop at start

u = Pseq([(1..4), (11..18)].flop, inf);
i = Pseq([0, 0, 1], inf).iter;

u.collect { |y| y[i.next] }.iter.nextN(20);

Variants of these approaches could also be done with Pindex.

1 Like

Pbinop(\at, Ptuple(patterns), indexPattern) is one solution I found. It was a little surprising to me that Pswitch1 can handle an array of patterns, but not a pattern which produces arrays, otherwise Pswitch1(Ptuple(patterns), indexPattern) would also work.

In context:

a = Pseq((1..4), 2); // [ 1, 2, 3, 4, 1, 2, 3, 4 ]
b = Pseq((11..18), 1); // [ 11, 12, 13, 14, 15, 16, 17, 18 ]
Pbinop(\at, Ptuple([a, b]), Pseq([0,0,1], 8)).asStream.nextN(8)
// -> [ 1, 2, 13, 4, 1, 16, 3, 4 ]
1 Like

Thanks @dkmayer, although the collect with i pre-converted to a stream isn’t what I wanted, nor will doing flop work, because I want it to work in general, not only with Pseq on arrays… (e.g. b might be a Pbrown – or anything)

@VIRTUALDOG your example with Pbinop does do exactly what I wanted, thanks!

// Example not using Pseq
a = Pn(Pgeom(1, 3, 4));
b = Pseed(123, Pbrown(-10, 0, 3));
x = Ptuple([a, b], inf);
i = Pseq([0, 0, 1], inf);
Pbinop(\at, x, i).iter.nextN(15)
// -> [ 1, 3, -5, 27, 1, -7, 9, 27, -4, 3, 9, -8, 1, 3, -7 ]

I also found another way (although like Daniel’s, it also requires getting the stream of indices beforehand), without going through Ptuple:

j = i.iter;
Preduce({ |...args| args[j.next] }, a, b).iter.nextN(15); // Preduce is from MathLib
// -> [ 1, 3, -5, 27, 1, -7, 9, 27, -4, 3, 9, -8, 1, 3, -7 ]

Thanks to both again for getting me unstuck!

1 Like

It’s too bad this doesn’t work with tuples either, this would have been most logical:

Pindex(x, i).iter.nextN(15)
// -> [ 1, 1, -5, 1, 1, -5, 1, 1, -5, 1, 1, -5, 1, 1, -5 ]