Все способы разделения массива (комбинации элементов) на пользовательский раздел - PullRequest
0 голосов
/ 07 декабря 2018

Я хочу разделить массив из n элементов на подмассивы заданного размера со всеми возможными комбинациями элементов.

Например:

Array: {1,2,3,4} - может быть n элементов, 1

Данный шаблон размера (только пример, может отличаться): [2 -subarrays, 2-elements]

Ожидаемый результат:

{1, 2}, {3,4}
{1,3}, {2,4}
{1,4}, {2,3}

или

{2,1}, {3,4}
{1,3}, {4,2}
{3,2}, {1,4}

и т. Д. Как видите, порядок элементов в подмассивах или порядок подмассивов в наборах подмассивов не имеет значения.Это должно быть минимальное количество наборов подмассивов входного массива.

Я получил решение ниже, но оно также включает перестановки.Мне нужно оптимизировать это, чтобы вообще не генерировать никаких перестановок.JavaScript не обязателен, подойдет любой язык.Заранее благодарю за любую помощь.

function getN(n, array, subsets) {
    var f,
        l = array.length,
        indices = [],
        temp;

    array = array.slice();
    while (l--) {
        f = factorial(l);
        indices.push(Math.floor(n / f));
        n %= f;
    }
    temp = indices.map(i => array.splice(i, 1)[0]);
    return subsets
        ? subsets.map((i => l => temp.slice(i, i += l))(0))
        : temp;


}

function factorial(num) {
    var result = 1;
    while (num) {
        result *= num;
        num--;
    }
    return result;
}

var i, l,
    array = ['1', '2', '3', '4'],
    subsets = [2, 2],
    pre = document.getElementById('out');

for (i = 0, l = factorial(array.length); i < l; i++) {
    pre.innerHTML += i.toString().padStart(4) +': ' + JSON.stringify(getN(i, array, subsets)) + '\n';
}

Ответы [ 2 ]

0 голосов
/ 08 декабря 2018

Я думаю, вы хотите n комбинаций массива.Вы можете сделать следующее:

Array.prototype.combinations = function(n){
  return this.reduce((p,c,i,a) => p.concat(n > 1 ? a.slice(i+1).combinations(n-1).map(e => [].concat(e,c))
                                                 : [[c]]),[]);
};

var result = [1,2,3,4].combinations(2);
console.log(JSON.stringify(result));
    result = [1,2,3,4,5,6].combinations(3);
console.log(JSON.stringify(result));
0 голосов
/ 08 декабря 2018

Вот рекурсивная формулировка, которая будет перечислять комбинации реальных элементов.В списке [2,2] каждый 2 считается отдельным элементом.Мы можем ввести произвольные шаблоны, такие как [1,2,3,4,5,6], разделенные на все комбинации с шаблоном [[x],[x,x],[x,x,x]].

function f(ns, subs){
  if (ns.length != subs.reduce((a,b) => a+b))
    throw new Error('Subset cardinality mismatch');

  function g(i, _subs){
    if (i == ns.length)
      return [_subs];

    let res = [];
    const cardinalities = new Set();

    function h(j){
      let temp = _subs.map(x => x.slice());
      temp[j].push(ns[i]);
      res = res.concat(g(i + 1, temp));
    }

    for (let j=0; j<subs.length; j++){
      if (!_subs[j].length && !cardinalities.has(subs[j])){
        h(j);
        cardinalities.add(subs[j]);

      } else if (_subs[j].length && _subs[j].length < subs[j]){
        h(j);
      }
    }
    return res;
  }
  let _subs = [];
  subs.map(_ => _subs.push([]));

  return g(0, _subs);
}

console.log('\n[0,1,2,3], [2,2]:');
let str = '';
for (let i of f([0,1,2,3], [2,2]))
  str += '\n' + JSON.stringify(i);
console.log(str);

console.log('\n[0,1,2,3], [1,3]:');
str = '';
for (let i of f([0,1,2,3], [1,3]))
  str += '\n' + JSON.stringify(i);
console.log(str);

console.log('\n[0,1,2,3,4,5,6,7,8,9], [1,2,3,4]:');
str = '';
for (let i of f([0,1,2,3,4,5,6,7,8,9], [1,2,3,4]))
  str += '\n' + JSON.stringify(i);
console.log(str);
...