Creating a new array with sub-arrays of size given by the original one

Hello,

Trying to create an array with sub-arrays of size given by the elements of the original array like this:
[ [ 1 ], [ 2, 3 ], [ 4, 5, 6, 7 ], [ 8, 9, 10, 11, 12, 13, 14, 15 ] ]
from:
[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15]
I came up with this:

(
a=[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15]; x = []; c = Pseq(a,1).asStream;
i = 0;
while ( { (a.at(i)) > 0 }, { (j=a.at(i)); k = [c.nextN(j)]; x = x ++ k; a=a.shift((a.at(i)).neg);});
x.postln
)

Which works, but in an example like this:

(
a = [ 3, 4, 2, 11, 8, 3, 1, 0, 7, 9, 6, 4, 4, 8, 1, 6, 5, 11, 8, 9 ]; x = []; c = Pseq(a,1).asStream;
i = 0;
while ( { (a.at(i)) > 0 }, { (j=a.at(i)); k = [c.nextN(j)]; x = x ++ k; a=a.shift((a.at(i)).neg);});
x.postln
)

I get : [ [ 3, 4, 2 ], [ 11, 8, 3, 1, 0, 7, 9, 6, 4, 4, 8 ], [ 1 ], [ 6, 5, 11, 8, 9, nil ] ]

which is supposed to be due to the .shift method I’m using. So my questions are:

  1. How could I chop off the “nil” results at the end?
  2. Is there a better way to get the result I need?
  3. and is there a way to get on the post window more elements instead of the “…etc…” when larger amounts of elements need to be displayed?

Thanks, I appreciate your help.
JF

  1. How could I chop off the “nil” results at the end?

Perhaps:

+ Object {
	nextNOrFewer {
		arg anInteger;
		var answer = List.new;
		anInteger.do({
			var next = this.next;
			(next == nil).ifTrue({ ^answer });
			answer.add(next);
		});
		^answer
	}
}
  1. Is there a better way to get the result I need?

This seems fine, but also once you have a stream you don’t need the array as well?

I.e. you could, if you liked, write a groupByPrefixCount method simply in terms of next?

  1. and is there a way to get on the post window more elements instead of the “…etc…” when larger amounts of elements need to be displayed?
(1 .. 200).asCompileString

Ps. You can also delete nils afterwards, i.e.

+ SequenceableCollection {
	takeUntilNil {
		var endIndex = this.indexOf(nil);
		(endIndex == nil).if({
			^this
		}, {
			^this.copyRange(0, endIndex - 1)
		})
	}
}

Thank you for such generous and accurate answers to all of my questions. The solution absolutely worked out. I appreciate that a lot. Regards, JF

Actually the method exists already:

a = [ [ 1 ], [ 2, 3 ], [ 4, 5, 6, 7 ], [ 8, 9, 10, 11, 12, 13, 14, 15 ] ];

b = (1..15).reshapeLike(a);

The most likely is to ‘postcs’ the result (“post compile-string”) – but make sure you don’t have an infinitely recursive data structure (you probably don’t).

hjh

but I think OP wanted the size of each subarray to to be determined by its first element!

Hm, if you have a stream, then iterating over it should be enough…?

(
var num, j, item, subarray;
a = [ 3, 4, 2, 11, 8, 3, 1, 0, 7, 9, 6, 4, 4, 8, 1, 6, 5, 11, 8, 9 ];
x = [];
c = Pseq(a, 1).asStream;
num = c.next;  // that's right, not within the loop
while {
    num.notNil and: { num > 0 }
} {
    j = 0;
    item = num;
    subarray = [];
    while {
        item.notNil and: { j < num }
    } {
        subarray = subarray.add(item);
        item = c.next;
        j = j + 1;
    };
    x = x.add(subarray);
    // moderate trickery:
    // item is now the start of the next subarray!
    // use this as num in the next cycle
    num = item;
};
// unsure if you want to add a partial subarray here

// final result
x
)

Haven’t tested but this should be pretty close. Edited because the subarray handling wasn’t right the first time.

Ah, my misreading. Hope the stream-iteration approach is helpful.

hjh

Here’s another version, which avoids the nested loop:

(
var remain, item, subarray;
a = [ 3, 4, 2, 11, 8, 3, 1, 0, 7, 9, 6, 4, 4, 8, 1, 6, 5, 11, 8, 9 ];
x = [];
c = Pseq(a, 1).asStream;
subarray = [];
remain = 0;
while {
	item = c.next;
	item.notNil
} {
	if(remain > 0) {
		subarray = subarray.add(item);
		remain = remain - 1;
	} {
		if(subarray.size > 0) {
			x = x.add(subarray);
		};
		subarray = [item];
		remain = item - 1;  // because we already took one
	};
};
// subarray is always initialized to at least one item
// therefore there is always something left to add here
x = x.add(subarray);

// final result
x
)

hjh

Thank you, James, for both insightful solutions, I appreciate them, regards, JF.