How to multiply arrays (or lists)?

Noobie question here:

Is there a method that will allow me to replicate an array a variable number of times?
I am thinking of an operator similar to python’s * , which you can apply to arrays:
[ 1 , 2, 3] * 3 ==> [1,2,3 ,1,2,3 ,1,2,3,]

My use case is that I have an array of arrays representing melodic cells and I want to to construct a sequence of pitches by repeating each subarray a random number of times and combining the result. Something like the following, let’s say (I’m omitting durations for simplicity):

~cells = [ [ 1, 3, 5, 7], [1, 3, 2]];
~minMax = [2,5] ;
~pitches = PSeq[~cells.collect({
                                     |item i|
                                     var reps;
                                     reps = rrand(minMax[0],minMax[1]);
                                     item * reps);            // <== does not work...
                                     }) ;
// Then PBind etc.   

I may be getting at this from a wrong angle, perhaps. Suggestions on better approaches gladly welcome.

Hello Cleinias,
surely there are better ways but you can do it like this:

(
~cells = [ [ 1, 3, 5, 7], [1, 3, 2]];
~minMax = [2,5] ;
~pitches = Pseq(
	~cells.collect({
		|item i|
		var reps;
		reps = rrand(~minMax[0], ~minMax[1]);
		item ! reps;
	}).flat.postln;
);
)

Thanks Kesey,

I had looked carefully at the docs before posting but could not find any mention of the ! operator. Wold you mind sharing how I could have found out?

Also, please do not keep me on edge on the better ways of doing this :wink:

http://doc.sccode.org/Overviews/SymbolicNotations.html#Miscellaneous%20operators

FWIW I (almost) rigorously avoid ! in my own code because it’s hard to find in the help – readability over concision.

In any case: Since the end goal is streaming, here are a couple of pattern-idiomatic ways:

~cells = [[1, 3, 5, 7], [1, 3, 2]];

(
Pswitch(
	~cells.collect { |cell| Pseq(cell, 1) },
	Pdup(
		Pwhite(2, 5, inf),
		Pn(Pseries(0, 1, ~cells.size), inf)
	)
)
.asStream.nextN(50)
)

(
Pflatten(1, Pdup(Pwhite(2, 5, inf), Pseq(~cells, inf)))
.asStream.nextN(50)
)

hjh

Thanks, your examples look much better indeed. Will delve into patterns further.

In SuperCollider:

[1, 2, 3] * 3 == [3, 6, 9]

and:

([1, 2, 3] ! 3).flatten == [1, 2, 3, 1, 2, 3, 1, 2, 3]

or longer:

[1, 2, 3].dup(3).flatten == [1, 2, 3, 1, 2, 3, 1, 2, 3]

You can give this a name if you like, including an operator name:

+ Array { !- { arg count; ^ (this ! count).flatten } }

After which:

[1, 2, 3] !- 3 == [1, 2, 3, 1, 2, 3, 1, 2, 3]

You can also give it a local name.

var df = {arg array, count; array.dup(count).flatten }; df.value([1, 2, 3], 3) == [1, 2, 3, 1, 2, 3, 1, 2, 3]

It depends how much you’re using it.

C.f. https://doc.sccode.org/Guides/WritingClasses.html#External%20method%20files

Ps. https://doc.sccode.org/Classes/Object.html#-dup

Oh, overlap, sorry. More characters to be long enough to send.

[1, 2, 3] ! 3

[1, 2, 3] dup: 3

[1, 2, 3].dup(3)

The ! operator is a shortcut for .dup

[1, 2, 3].dup(3).flat.sum

-> 18

It’s only documented for class Function, though it’s also included as an instance method for class Object… so it applies to everything.

It’s often used for Multichannel Expansion… the ! operator will always return it’s results in a single collection.