1

Source Arrays:

var arr1 = ["a", "b"];
var arr2 = ["c"];
var arr3 = ["d", "e", "f"];

I can do permutations:(No duplicate)

["a", "c", "d"], 
["b", "c", "d"], 
["b", "c", "e"],
["b", "c", "f"],
["a", "c", "e"],
["a", "c", "f"]

But how can I get the results permutation like?

["a", "c"],
["a", "d"], 
["a", "e"],
["a", "f"],
["b", "c"],
["b", "d"],
["b", "e"],
["b", "f"],
["c", "d"],
["c", "e"],
["c", "f"]

I only got my single array permutation snippet here

var arr3 = ['d', 'e', 'f'];

function permutation (list, n) {
    var results = []
    function _perm (list, n, res, start) {
        if (res.length === n) {
            return results.push(res.join(','))
        }
        if (start === list.length) { return }
        _perm(list, n, res.slice(), start + 1)
        res.push(list[start])
        _perm(list, n, res, start + 1)
    }
    _perm(list, n, [], 0)
    return results
}
console.log(permutation(arr3, 2)) // print ["e,f", "d,f", "d,e"]

Because of the source arrays could be unlimited, I need to combine and permute them at the same time. I would like to know what is the best to achieve like this:

var arr1 = ['a', 'b'];
var arr2 = ['c'];
var arr3 = ['d', 'e', 'f'];
...
var arrN = ['x', 'y', 'z'];

permutation([arr1, arr2, arr3, arr4], 2)
permutation([arr1, arr2, arr3, arr4], 3)
permutation([arr1, arr2, arr3, arr4], 4)

I really appreciate any helps.

Bergi
  • 630,263
  • 148
  • 957
  • 1,375
DAVE
  • 111
  • 11
  • You want combinations or permutations? –  Jun 23 '20 at 19:48
  • Does this answer your question? [JavaScript - Generating combinations from n arrays with m elements](https://stackoverflow.com/questions/15298912/javascript-generating-combinations-from-n-arrays-with-m-elements) – Heretic Monkey Jun 23 '20 at 20:13
  • This doesn't look like permutations at all. More like combinations from all subsequences of length 2. – Bergi Jun 23 '20 at 20:54
  • @ParthVaswani I will say I need a permutation in combination in this case. – DAVE Jun 24 '20 at 07:52
  • @HereticMonkey Yes, it does combine the arrays, but still need permutation with specific element or size in turns. – DAVE Jun 24 '20 at 07:57
  • @Bergi Its like combinations without Repetition from N arrays and then permute it with size in return. – DAVE Jun 24 '20 at 08:03
  • @DAVE Can you please spell out the complete result of your example? It still doesn't look like you want permutations if `a` never comes before `c`/`d`/`e`. Also, where does `f` come from ?! – Bergi Jun 24 '20 at 08:24
  • @DAVE I have adjusted the code and it ignores self permutation have you checked it out? – Sven.hig Jun 24 '20 at 08:28
  • 1
    @Bergi oh..missing 'f' in arr3. I will update the question with results shortly. – DAVE Jun 24 '20 at 09:38
  • Thanks for the clarification. Yes, that's not a [permutation](https://en.wikipedia.org/wiki/Permutation) – Bergi Jun 24 '20 at 11:39

2 Answers2

2

You are looking to get the subsets of length N from your selection of arrays, then create the cartesian product of each subset.

// returns power set of arr filtered by length
function powerset(arr, len, pref=[]) {
    if (len == 0) return [pref];
    if (len > arr.length) return [];
    if (len == arr.length) return [pref.concat(arr)]; // premature optimisation
    const next = arr.slice(1);
    return powerset(next, len-1, [...pref, arr[0]]).concat(powerset(next, len, pref));
}
// returns cartesian product of the arrays in the argument
function cartesian(arg) {
    var r = [], max = arg.length-1;
    function helper(arr, i) {
        for (var j=0, l=arg[i].length; j<l; j++) {
            var a = arr.slice(0); // clone arr
            a.push(arg[i][j]);
            if (i==max)
                r.push(a);
            else
                helper(a, i+1);
        }
    }
    helper([], 0);
    return r;
}
var arrays = [
  ['a', 'b'],
  ['c'],
  ['d', 'e', 'f'],
  ['x', 'y', 'z']
];
console.log(powerset(arrays, 2).flatMap(cartesian));
console.log(powerset(arrays, 3).flatMap(cartesian));
console.log(powerset(arrays, 4).flatMap(cartesian));
Bergi
  • 630,263
  • 148
  • 957
  • 1,375
  • Very interesting, I have been learning a lot from this, also it was very nice of you checking the length of arrays at the first block. I believe this is the answer for me. – DAVE Jun 25 '20 at 17:19
0

here is the code without eval

var arr1 = ['a', 'b'];
var arr2 = ['c'];
var arr3 = ['d', 'e', 'f'];
var arr4 = ['x', 'y', 'z'];

comb=[arr1,arr2,arr3,arr4]
conc=comb.flat()
resx=[]
  function permut(){ // number of arrays
        for(let i=0;i<conc.length;i++){
          for(let j=i+1;j<conc.length;j++){
             b=[conc[i],conc[j]]
               comb.forEach(x=>{
                 if (x.includes(conc[i]) && !x.includes(conc[j])) resx.push(b)

              })
          }
        }
  }
  permut()
console.log(resx)
Sven.hig
  • 4,449
  • 2
  • 8
  • 18
  • I'm pretty certain that the OP does not want to use `eval` – Bergi Jun 23 '20 at 21:38
  • and why is that ? the code works as expected, getting a downvote for using `eval` is really unfair – Sven.hig Jun 23 '20 at 21:40
  • `eval` has risks but not in this situation as far as i know – Sven.hig Jun 23 '20 at 21:41
  • It's just [a bad practice in general](https://stackoverflow.com/q/86513/1048572), and should absolutely not be necessary here. – Bergi Jun 23 '20 at 21:42
  • @Sven.hig Thanks man, but the each array can NOT be self-permutation, it goes only in between which means such as [a,b] [d, e] [e f]...were incorrect. – DAVE Jun 24 '20 at 03:41
  • @DAVE I have adjusted the answer as you requested, check it out and tell me if it works for you – Sven.hig Jun 24 '20 at 04:55
  • 1
    @Sven.hig Considering the number of arrays could vary, is it possible to loop the length of array instead of declarations string? – DAVE Jun 24 '20 at 09:31
  • @Dave you can use any number of arrays with different lengths with this code it's going to work – Sven.hig Jun 24 '20 at 09:35
  • @Sven.hig Just use an array of arrays instead of the horrible `eval` and it will become obvious! – Bergi Jun 24 '20 at 10:01
  • 1
    @Bergi Please feel free to recommend any more changes or improvements needed – Sven.hig Jun 24 '20 at 12:25
  • Thanks. The problem with your solution is that it doesn't work when the values in the input arrays are not distinct. – Bergi Jun 24 '20 at 12:31
  • Your are welcome, I believe if the values are not distinct then there is no way to preserve the order (permutation), In fact it will be meaningless to make subsets of the nature of what OP is asking, please correct me if I am wrong – Sven.hig Jun 24 '20 at 12:42
  • @Sven.hig Thank you, pal. you get rid of eval :p Sorry I did not ask question clearly, and Bergi saw my desired outputs at the last paragraph of the question. I really appreciate your help. – DAVE Jun 25 '20 at 17:40