Velocity Reviews > Looping through variable number of arrays variable times?

# Looping through variable number of arrays variable times?

Mike P
Guest
Posts: n/a

 10-22-2005
I will be passing my function a two dimensional array of varying length.
Within that array is one data point, and the number of times it should loop
through.

So, for example, I might pass this to the function:

example[0] = new Array("A",2);
example[1] = new Array("Q",4);
function loopIt(example);

The function will then do the following:

function loopIt(example) {
for (x1 = 0; x1 < example[0][1]; x1++) {
for (x2 = 0; x2 < example[1][1]; x2++) {
calculateArray = new Array(example.length);
calculateArray[0] = new Array(example[0][0],x1);
calculateArray[1] = new Array(example[1][0],x2);
calculate(calculateArray);
}
}
}

But loopIt() doesn't know what example.length will be. Here I showed
example.length = 2. But if example.length = 41, this function wouldn't
work. How can I create a loop like this when example.length will vary?

Thanks!

Mike

VK
Guest
Posts: n/a

 10-22-2005

Mike P wrote:
> example[0] = new Array("A",2);
> example[1] = new Array("Q",4);
> function loopIt(example);
>
> The function will then do the following:
>
> function loopIt(example) {
> for (x1 = 0; x1 < example[0][1]; x1++) {
> for (x2 = 0; x2 < example[1][1]; x2++) {
> calculateArray = new Array(example.length);
> calculateArray[0] = new Array(example[0][0],x1);
> calculateArray[1] = new Array(example[1][0],x2);
> calculate(calculateArray);
> }
> }
> }
>
> But loopIt() doesn't know what example.length will be. Here I showed
> example.length = 2. But if example.length = 41, this function wouldn't
> work. How can I create a loop like this when example.length will vary?

That means that your array elements are going by pairs: example[i][1]
gives you the value for external loop, example[i+1][1] gives you the
value for internal value. So there is no way your array may contain an
odd amount of elements. Is it correct?

Mike P
Guest
Posts: n/a

 10-22-2005

"VK" <(E-Mail Removed)> wrote in message
news:(E-Mail Removed) oups.com...

> That means that your array elements are going by pairs: example[i][1]
> gives you the value for external loop, example[i+1][1] gives you the
> value for internal value. So there is no way your array may contain an
> odd amount of elements. Is it correct?

With the code sample, the "example" array can contain 1 to 41 elements (even
or odd), but each array within it will be 2 long.

So:
example.length = 0 to 41 elements, and any integer inbetween (even or odd)
but example[x].length will always = 2 where
example[x][0] will always contain a string and
example[x][1] will contain an integer between 0 and 8

If I were to code this a long and ugly way, I could create a switch based on
example.length like this:

function loopIt(example) {

switch(example.length) {
case 1:
for (x1 = 0; x1 < example[0][1]; x1++) {
calculateArray = new Array(example.length);
calculateArray[0] = new Array(example[0][0],x1);
calculate(calculateArray);
}
}
break;
case 2:
for (x1 = 0; x1 < example[0][1]; x1++) {
for (x2 = 0; x2 < example[1][1]; x2++) {
calculateArray = new Array(example.length);
calculateArray[0] = new Array(example[0][0],x1);
calculateArray[1] = new Array(example[1][0],x2);
calculate(calculateArray);
}
}
}
break;
case 3:
for (x1 = 0; x1 < example[0][1]; x1++) {
for (x2 = 0; x2 < example[1][1]; x2++) {
for (x3 = 0; x3 < example[2][1]; x3++) {
calculateArray = new Array(example.length);
calculateArray[0] = new Array(example[0][0],x1);
calculateArray[1] = new Array(example[1][0],x2);
calculateArray[2] = new Array(example[2][0],x3);
calculate(calculateArray);
}
}
}
break;
}
}

So on, and so forth up to case 41, but that seems excessively inefficient.
I'm hoping there's a cleaner way to accomplish this.
do you follow?

I imagine there's some way to do this with a recursive array or dynamically
creating the function (ala, new Function)... I just don't really understand

Thanks for your help on this!

Mike

VK
Guest
Posts: n/a

 10-22-2005
> I imagine there's some way to do this with a recursive array or dynamically
> creating the function (ala, new Function)... I just don't really understand
> how to go about it.

Well, using runtime generated function:

<html>
<title>Test</title>
<meta http-equiv="Content-Type" content="text/html;
charset=iso-8859-1">
<script type="text/javascript">
var example = new Array();
example[0] = new Array('Q',2);
example[1] = new Array('A',4);
example[2] = new Array('B',3);

function test() {
var fun = null;
var funOpen = '';
var funBody = '';
var funEnd = '';
var x = '';
var space = '';
var len = example.length;

for (i=0; i<len; i++) {
x = 'x'+(i+1);
funOpen+= space+'for ('+x+'=0; '+x+'<arr['+i+'][1]; '+x+'++) {\n';
funEnd += '}';
space+= ' ';
}

funBody+= space+'calculateArray = new Array(arr.length);\n';
for (i=0; i<len; i++) {
x = 'x'+(i+1);
funBody+= space+'calculateArray['+i+'] = new
Array(arr['+i+'][0],'+x+');\n';
}
funBody+= space+'calculate(calculateArray);\n';
fun = new Function('arr',funOpen.concat(funBody,funEnd));
fun(example);
}

function calculate(foo) {
}
</script>

</body>
</html>

I would not say that it's any less ugly than 41 case, but definitely
shorter.
I guess any math prof would kill me for the above. The total amount of
loops is factorial of [i][1] values in your array. It's a strong hint
that the problem could be solved in some nice and profoundly academical
way using recursions. But it requires good matrix math knowledge more
than any JavaScript skills. The last of fine by me, the first is
floating miserably
It works any way...

Mike P
Guest
Posts: n/a

 10-22-2005
Wow... very cool! You rule!

I'm going to have to study that a bit to figure out how you did it.

Thanks again!

Mike

"VK" <(E-Mail Removed)> wrote in message
news:(E-Mail Removed) oups.com...
>> I imagine there's some way to do this with a recursive array or
>> dynamically
>> creating the function (ala, new Function)... I just don't really
>> understand
>> how to go about it.

>
> Well, using runtime generated function:
>
> <html>
> <title>Test</title>
> <meta http-equiv="Content-Type" content="text/html;
> charset=iso-8859-1">
> <script type="text/javascript">
> var example = new Array();
> example[0] = new Array('Q',2);
> example[1] = new Array('A',4);
> example[2] = new Array('B',3);
>
> function test() {
> var fun = null;
> var funOpen = '';
> var funBody = '';
> var funEnd = '';
> var x = '';
> var space = '';
> var len = example.length;
>
> for (i=0; i<len; i++) {
> x = 'x'+(i+1);
> funOpen+= space+'for ('+x+'=0; '+x+'<arr['+i+'][1]; '+x+'++) {\n';
> funEnd += '}';
> space+= ' ';
> }
>
> funBody+= space+'calculateArray = new Array(arr.length);\n';
> for (i=0; i<len; i++) {
> x = 'x'+(i+1);
> funBody+= space+'calculateArray['+i+'] = new
> Array(arr['+i+'][0],'+x+');\n';
> }
> funBody+= space+'calculate(calculateArray);\n';
> fun = new Function('arr',funOpen.concat(funBody,funEnd));
> fun(example);
> }
>
> function calculate(foo) {
> }
> </script>
>
>
> </body>
> </html>
>
> I would not say that it's any less ugly than 41 case, but definitely
> shorter.
> I guess any math prof would kill me for the above. The total amount of
> loops is factorial of [i][1] values in your array. It's a strong hint
> that the problem could be solved in some nice and profoundly academical
> way using recursions. But it requires good matrix math knowledge more
> than any JavaScript skills. The last of fine by me, the first is
> floating miserably
> It works any way...
>

RobG
Guest
Posts: n/a

 10-24-2005
VK wrote:
>>I imagine there's some way to do this with a recursive array or dynamically
>>creating the function (ala, new Function)... I just don't really understand

>
>
> Well, using runtime generated function:

[...]
>
> I would not say that it's any less ugly than 41 case, but definitely
> shorter.
> I guess any math prof would kill me for the above. The total amount of
> loops is factorial of [i][1] values in your array. It's a strong hint
> that the problem could be solved in some nice and profoundly academical
> way using recursions. But it requires good matrix math knowledge more
> than any JavaScript skills. The last of fine by me, the first is
> floating miserably
> It works any way...
>

There *had* to be a better way. This bugged me for hours, here's one
that may do the job better and could be considered 'better' - it
iterates through the first array of arrays and keeps splicing in
elements. I think the use of concat() and splice() may restrict it to

The function copyA() copies a 1D array, it shouldn't be used with 2D (or
more) arrays.

I can think of a faster way - go through the first set of loops for the
first loop (A[0]), then just copy those for every subsequent loop. But
I'll leave the implementation up to the OP.

The result is a 2D array:

<script type="text/javascript">
var A = [
['Q',2]
,['A',4]
,['B',2]
,['C',2]
];

// This does some setup
function doLoops(A)
{
var B=[];
for (var i=0, aLen=A.length; i<aLen; ++i){
}
}

// The real work happens here
{
var c = A[i][0];

if (0 == i){ // Do first case
for (var j=0, aLen=A[i][1]; j<aLen; ++j){
B[j]=[c, j];
}
return;
} else { // All all others
var root // root array
var loops=A[i][1]; // Number of loops

for (var k=0, bLen=B.length; k<bLen; ++k){
root = copyA(B[k*loops]);

for (var m=0; m<loops; ++m){
if (0==m){
B[k*loops] = root.concat(c, m);
} else {
B.splice((k*loops + m),0,root.concat(c, m));
}
}
}
}
return;
}

// Return a copy of a 1 dimensional array (vector)
// If a 2d array is passed, references are returned
// not a proper copy.
function copyA(A)
{
var x = [];
var i = A.length;
while( i--){ x[i] = A[i]; }
return x;
}
</script>

--
Rob

RobG
Guest
Posts: n/a

 10-24-2005
RobG wrote:
[...]

> I can think of a faster way - go through the first set of loops for the
> first loop (A[0]), then just copy those for every subsequent loop. But
> I'll leave the implementation up to the OP.

This one is a bit faster and a lot tidier, it uses concat to copy the
array instead of copyA, everything is in one function.

<script type="text/javascript">

var A = [['Q',2],['A',4],['B',3]];

function doLoops(A)
{
var B=[];
var c=A[0][0];
var loops=A[0][1];

// Seed B
for (var j=0; j<loops; ++j){
B[j] = [c, j];
}

for (var i=1, aLen=A.length; i<aLen; ++i){
c = A[i][0];
loops = A[i][1];
for (var k=0, bLen=B.length; k<bLen; ++k){
var root = B[k*loops].concat(c);
for (var m=0; m<loops; ++m){
B.splice((k*loops + m),(!m),root.concat(m));
}
}
}

// For show
document.getElementById('zz').innerHTML =
'A: ' + A + '<br>' +
'Elements: ' + B.length + '<br>' + B.join('<br>');

return B;
}

</script>

<div id="zz"></div>
</body></html>

[...]

--
Rob

Julian Turner
Guest
Posts: n/a

 10-24-2005

Mike P wrote:

> I will be passing my function a two dimensional array of varying length.
> Within that array is one data point, and the number of times it should loop
> through.
>
> So, for example, I might pass this to the function:
>
> example[0] = new Array("A",2);
> example[1] = new Array("Q",4);
> function loopIt(example);
>
> The function will then do the following:
>
> function loopIt(example) {
> for (x1 = 0; x1 < example[0][1]; x1++) {
> for (x2 = 0; x2 < example[1][1]; x2++) {
> calculateArray = new Array(example.length);
> calculateArray[0] = new Array(example[0][0],x1);
> calculateArray[1] = new Array(example[1][0],x2);
> calculate(calculateArray);
> }
> }
> }
>
> But loopIt() doesn't know what example.length will be. Here I showed
> example.length = 2. But if example.length = 41, this function wouldn't
> work. How can I create a loop like this when example.length will vary?
>
> Thanks!

If I have understood the problem correctly, here is a further addition
to all the other contributions - a method using recursion:-

function LoopIt(e)
{
this.example=e;
this.exampleLength=e.length;
this.indexArray=[];

this.recurse(0);
}

LoopIt.prototype.recurse=function(n)
{
if (n<this.exampleLength)
{
var m=n+1;

for (var i=0; i<this.example[n][1]; i++)
{
this.indexArray[n]=i;
this.recurse(m);
}
return;
}

var a=[];

for (var i=0; i<this.exampleLength; i++)
{
a[i]=new Array(this.example[i][0],this.indexArray[i]);
}

calculate(a);
};

var example=[];
example[0] = new Array("A",2);
example[1] = new Array("Q",4);

var l=new LoopIt(example); // Constructs and calls

Julian

Mike P
Guest
Posts: n/a

 10-24-2005
"RobG" <(E-Mail Removed)> wrote in message
news:JP%6f.1122\$(E-Mail Removed)...

> This one is a bit faster and a lot tidier, it uses concat to copy the
> array instead of copyA, everything is in one function.

RobG, et al,

I'm glad to know this was an interesting intellectual challenge to even the
pros... I was completely stumped. I'll play around with the different
approaches (run time compile, join/concat, and recursive object function) to
figure out, not only which I'll actually use, but to learn how they work.

Thanks again, to all!

Mike

RobG
Guest
Posts: n/a

 10-26-2005
Mike P wrote:
> "RobG" <(E-Mail Removed)> wrote in message
> news:JP%6f.1122\$(E-Mail Removed)...
>
> > This one is a bit faster and a lot tidier, it uses concat to copy the
> > array instead of copyA, everything is in one function.

>
> RobG, et al,
>
> I'm glad to know this was an interesting intellectual challenge to even the
> pros... I was completely stumped. I'll play around with the different
> approaches (run time compile, join/concat, and recursive object function) to
> figure out, not only which I'll actually use, but to learn how they work.
>
> Thanks again, to all!
>
> Mike

Hey, just for the record, here's a recursive version (sorry, couldn't
help myself, this just kept popping into my brain!).

var A = [['Q',2],['A',4],['B',3]];

function recA(X, i, B)
{
var i = i || 0;
if (!B) B = [[]];
var root = B[B.length-1].concat(X[i][0]);
var loops = X[i][1];
for (var j=0; j<loops; ++j){
B.splice((B.length-1+j), (!j), root.concat(j));
if ( X[i+1] ) recA(X, i+1, B);
}
return B;
}

--
Rob