2

I am quite fresh with programming and I am working on some code to generate various values for my thesis. Having spent several days searching for an answer to my problem without much success, I am hoping this community might be able to provide some insight.

Short version: Make the code below independent of the input array arr's length.

Longer version:

I have an array of arrays, arr = [a, b, c, d], as input to a function where I would like to calculate all possible combinations (i.e. a1,b1,c1,d1, a2,b1,c1,d1, etc.) without having to know the definite number of elements in arr.

The problem is that the results are dependent on each element's position in arr. In other words, the name of each array in arr (a, b, c, d) has to be able to be referenced in the results. For clarity's sake, say that arr=[oil_price, countries, vessel_types]. Then, it wouldn't make much sense if the results came out randomized, and not in the same order, such as:

[ country[1], oil_price[1], vessel_type[1] ] (first pass)

[ vessel_type[2], country[1], oil_price[1] ] (second pass)

The code below does take the element position in arr into account and creates the resultspace I would like, but requires a for loop for each element, which is what I am trying to avoid as the number of elements in arr could vary from time to time.

function resultspace(arr){
results = [];
e_id = 1;
for (count_1 = 0; count_1 < arr[0].length; count_1++){
    for (count_2 = 0; count_2 < arr[1].length; count_2++){
        for (count_3 = 0; count_3 < arr[2].length; count_3++){
            for (count_4 = 0; count_4 < arr[3].length; count_4++){
                for (count_5 = 0; count_5 < arr[4].length; count_5++){
                    for (count_6 = 0; count_6 < arr[5].length; count_6++){
                        id = e_id
                        var1 = arr[0][count_1].value;
                        var2 = arr[1][count_2].value;
                        var3 = arr[2][count_3].value;
                        var4 = arr[3][count_4].value;
                        var5 = arr[4][count_5].value;
                        var6 = arr[5][count_6].value;

                        result_instance = {id:e_id,
                                            VAR1: var1, 
                                            VAR2: var2, 
                                            VAR3: var3, 
                                            VAR4: var4, 
                                            VAR5: var5, 
                                            VAR6: var6
                                            };
                        results.push(result_instance);
                        e_id++;
                    };
                };
            };
        };
    };
return(results);
};
};

I have looked into recursive combination generation here and here, but I haven't been able to take the element position of the input array into account using these methods.

Thank you for reading.

Community
  • 1
  • 1
  • I asked a very similar question once, check out the answers there (https://stackoverflow.com/questions/9129116/dynamic-for-loop-structure) – epoch May 19 '14 at 12:50

1 Answers1

0
  1. You want names so you need to use Map instead of Array.
  2. You need to provide names as Array since the order of for-in loops is not guaranteed.

Working demo http://jsfiddle.net/tarabyte/VLj7J/. Works in modern browsers.

function permutate(arrays, keys, memo) {
    var options, name;

    if(keys.length ) {
        name = keys.shift();
        options = arrays[name];
        memo = memo || [{}];
        return permutate(arrays, keys, options.reduce(function(all, item){
            return all.concat(memo.map(function(curr){
                var result = copy({}, curr);
                result[name] = item;
                return result;
            }));
        }, []));
    }

    return memo;
}

Call it as follows

permutate({name: [], age: [], gender: []}, ['age', 'name', 'gender']);

Function copy

function copy(to, from) {
    Object.keys(from).forEach(function(key){
        to[key] = from[key];
    });
    return to;
}

Or an array of {name: []} pairs with additional preprocessing http://jsfiddle.net/tarabyte/VLj7J/2/.

function permutate(data, memo) {
    var options, name;

    if(data.length ) {
        options = data.shift();
        for(name in options){
            options = options[name];
        }
        memo = memo || [{}];
        return permutate(data, options.reduce(function(all, item){
            return all.concat(memo.map(function(curr){
                var result = copy({}, curr);
                result[name] = item;
                return result;
            }));
        }, []));
    }

    return memo;
}
Yury Tarabanko
  • 44,270
  • 9
  • 84
  • 98