生成多数组的排列

时间:2018-05-20 11:24:39

标签: javascript algorithm permutation

我想在javascript(或算法)中生成多数组中元素的所有排列:

输入:

[
  ['a', 'b', 'c', 'd'],
  ['e', 'f', 'g'],
  ['h', 'i']
]

输出:

[
  ['a', 'e', 'h'],
  ['a', 'e', 'i'],
  ['a', 'f', 'h'],
  ...
  ['d', 'g', 'i']
]

注意:我不想要[' a',' b',' c'的排列, ' d''' f',' g',' h',' i& #39;]因为我不想要这样的结果:[' a',' b',' c']。

Note2 :我只对支持N维数组输入的解决方案感兴趣。

谢谢!

4 个答案:

答案 0 :(得分:1)

 function mutate(array) {
   if(array.length === 1)
      return array[0].map(el => [el]);
   const mutations = mutate(array.slice(1));
   const result = [];
   for(const el of array[0])
     for(const rest of mutations)
       result.push([el, ...rest]);
   return result;
}

这是一种递归方法。

答案 1 :(得分:1)

如果您喜欢函数式编程,可以在Array类型上使用lift。就我而言,我为了简单起见使用了RamdaJS

const input = [
  ['a', 'b', 'c', 'd'],
  ['e', 'f', 'g'],
  ['h', 'i']
]

const output = R.lift ( ( x, y, z ) => [ x, y, z ] ) ( ...input )

console.log( output )
<script src="https://cdnjs.cloudflare.com/ajax/libs/ramda/0.25.0/ramda.min.js"></script>

这是一个普通的JavaScript lift3实现:

const input = [
  ['a', 'b', 'c', 'd'],
  ['e', 'f', 'g'],
  ['h', 'i']
]

const flatten = array => [].concat.apply ( [], array )

// Array#flatMap please! ;-)
const ap = funs => array => flatten ( funs.map ( f => array.map ( f ) ) )

const lift3 = f => array1 => array2 => array3 => 
                ap ( ap ( array1.map ( f ) ) ( array2 ) ) ( array3 )

const output = lift3 ( x => y => z => [ x, y, z ] ) ( input[0] ) ( input[1] ) ( input[2] )

console.log( output )

答案 2 :(得分:1)

您似乎感兴趣的是套装的笛卡尔积。输出的长度将是集合长度的乘积,我们可以通过以下方法导出任意输出列表中每个元素的列表索引:

// i is the zero-based ouput-list index
// p is the product of input set lengths
function unrank(i, input, p){
  let output_list = new Array(input.length);

  for (let k=0; k<input.length; k++){
    p = Math.floor(p / input[k].length);
    let m = Math.floor(i / p);
    i = i - m * p;
    output_list[k] = input[k][m];
  }
  
  return output_list;
}

var input = [
  ['a', 'b', 'c', 'd'],
  ['e', 'f', 'g'],
  ['h', 'i']
];

// Output
var prod = input.map(x => x.length).reduce((a, b) => a * b);

console.log(unrank(23, input, prod));
console.log(unrank(11, input, prod));

要列出所有内容,请将索引从0循环到(输入集长度的乘积 - 1)。

答案 3 :(得分:0)

您可以使用迭代和递归方法。

var d = [['a', 'b', 'c', 'd'], ['e', 'f', 'g'], ['h', 'i']],
    processor = array => {
         var result = [],
             iter = p => p.length < array.length
                ? array[p.length].forEach(v => iter(p.concat(v)))
                : result.push(p);

        iter([]);
        return result;
    };

console.log(processor(d).map(a => a.join(' ')));
.as-console-wrapper { max-height: 100% !important; top: 0; }

更短的方法

var d = [['a', 'b', 'c', 'd'], ['e', 'f', 'g'], ['h', 'i']],
    result = d.reduce(
        (a, b) => a.reduce(
            (r, v) => r.concat(b.map(w => [].concat(v, w))),
            []
        )
    );

console.log(result.map(a => a.join(' ')));
.as-console-wrapper { max-height: 100% !important; top: 0; }