Notifications
Clear all

[Closed] Collect nested for loops to a single flat array?

Is there a simple way to do this?

For example, the following line:

for i = 1 to 5 collect (for j = 1 to 3 collect (i * j))

returns a multidimensional array of #(#(1, 2, 3), #(2, 4, 6), #(3, 6, 9), #(4, 8, 12), #(5, 10, 15))

But what I want is just a one dimensional array of all the collected values in sequence, i.e. #(1, 2, 3, 2, 4, 6, 3, 6, 9, 4, 8, 12, 5, 10, 15)

Up until now I’ve just been using the format of

(
	testArray = #(); for i = 1 to 5 do (for j = 1 to 3 do append testArray (i * j))
	testArray
)

which seems to be a cumbersome way to get the results I’m looking for. So, is there a better way to do this?

5 Replies
1 Reply
(@denist)
Joined: 10 months ago

Posts: 0

there is no better way.

Good to know, thanks!

1 Reply
(@bobo)
Joined: 10 months ago

Posts: 0

To expand on what Denis said, there IS another variation of what you did there, but it turned out to be over 3 times slower, probably due to the different memory management / garbage collection behavior.

Your expression grows the array one item at a time via append.

The following builds an array in the inner loop, then joins it to the big flat array, thus growing two arrays in large chunks. With 1000×1000 iterations, your expression takes about a second, while the following takes about 3.5 (on my 2 core laptop):

testArray = #(); for i = 1 to 1000 do join testArray (for j = 1 to 1000 collect (i * j))

Also, it does not look any more elegant than your solution.
So stick to the fastest method

you can force max to do just one allocation

a = #();
a.count = 5 * 3; 
i = 1;
for j = 1 to 5 do for k = 1 to 3 do ( a[i] = (k * j); i += 1; )
a

might win out if the numbers get big

1 Reply
(@bobo)
Joined: 10 months ago

Posts: 0

Actually I tested this as part of the other two test runs and it was about half way between the two time-wise (about 2 seconds for 1000×1000 iterations on my laptop).

Even without the index counter, it is not faster than the append() method – I got it down to about 1.8 seconds per million iterations.

(
	a = #()
	a.count = 5 * 3
	for j = 1 to 5 do for k = 1 to 3 do ( a[(j-1)*3+k] = (k * j) )
	a
)

Since these look even less stylish (smell a lot like MEL to me ), I decided to omit them.
Thanks for mentioning that option!