Collect single item

hey, just a simple question about using collect.

i have this function:

(
var f = { |freqs|
	freqs.collect { |freq|
		freq * (1..16);
	}.flop;	
};

var freqs = [440, 440, 440, 440, 440];

f.(freqs);
)

and would also like to have the possibility to just pass a single item instead of an array.
The result should look like this:

(
var f = { |freq|
	freq * (1..16);	
};

var freq = 440;

f.(freq);
)

is it possible to have the first one behave like the second one when only a single item is passed? thanks

do i have to use if here?

(
var f = { |freqs|
	var ratios = (1..16);
	if( freqs.size == 0, 
		
		{ 
			freqs * ratios
		},
		
		{ 
			freqs.collect { |freq|
				freq * ratios;
			}.flop;			
		}
	);
	
};

var freqs = [440, 440, 440, 440, 440];

f.(freqs);
)

Something like that:

(
var f = { |freq|
	if(freq.isArray)
	{
		freq.collect{|frq|frq * (1..16)}.flop
	}
	{
		freq * (1..16)
	}
};
)

:slightly_smiling_face:

thanks :slight_smile: i was also thinking about this and thought there would be another solution beside if.

Without if the result needs to be “normalized” as an array of arrays:

(
var f = { |freq|
	freq.asArray.collect{|frq|frq * (1..16)}.flop
};
)

It can be helpful to write up a spec of exactly what you want for types of input.

Presumably:

  • f.value(number) – you’d like an array consisting of each 1…16 element times the number.

  • f.value(array) – an array of arrays, consisting of each array element times 1…16… that is, the two arrays would be multiplied into a table – 1…16 across the top, the input array down the side.

This isn’t convenient to search in the help, but in fact SC does support table-style math ops on arrays.

f = { |x| x *.t (1..16) };

See Adverbs for Binary Operators | SuperCollider 3.12.2 Help.

(BTW what if you table-multiply a number by (1…16)? It just gives you a single row, not as a nested array. So it matches the spec.)

::slight_smile:

1 Like

thanks, there is one adjustment to the specifications:

f.value(number) should return a single array with 1…16 elements times the number. check!

but f.value(array) should return an array of 16 arrays, where each array of arrays has input.size times the n-element

using flop gives me the desired result for f.value(array)

(
f = { |x| 
	(x *.t (1..16)).flop;
};

f.([440, 440, 440, 440, 440]);
)

but for f.value(number) it should return a flat array, so no flop:

(
f = { |x| 
	(x *.t (1..16));
};

f.(440);
)

Go back and take another look at my post: “1…16 across the top, the input array down the side.”

Now look at the expression: f = { |x| x *.t (1..16) }; – so the “across the top” (rows) is the second operand, and “down the side” (columns) is the first operand.

What you’re saying here is that you want 1…16 down the side (columns), and the input array across the top (rows).

And we know that the expression is written in terms of columns *.t rows.

Now… given that, do you think you can adapt the *.t expression on your own?

hjh

1 Like

thank you very much. it works for both cases when exchanging the input data for columns and rows:

f = { |x| (1..16) *.t x };