将数组(元素组合)划分为自定义分区的所有方式

Posted

技术标签:

【中文标题】将数组(元素组合)划分为自定义分区的所有方式【英文标题】:All ways of dividing an array (element combinations) into a custom partition 【发布时间】:2019-05-09 00:59:54 【问题描述】:

我想用所有可能的元素组合将包含 n 个元素的数组划分为给定大小的子数组。

例如:

数组: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';
&lt;pre id="out"&gt;&lt;/pre&gt;

【问题讨论】:

一个简单(但未优化)的解决方案是从结果数组中删除排列。 是的,我知道,但我正在寻找快速优化的解决方案,而不是生成排列。 有什么限制? Pham Trung,你说的约束是什么意思? 不,它不是重复的。这与这个问题相反。我需要摆脱排列,而不是做出排列。 【参考方案1】:

我猜你想要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));

【讨论】:

与我的回答不同,这不允许像 [1,2,3,4,5,6] 这样的任意模式分为模式 [[x],[x,x] 的组合, [x,x,x]]。 想一想,我不确定这是否真的回答了这个问题。【参考方案2】:

这是一个递归公式,它将枚举实际元素的组合。在列表[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);

【讨论】:

不错的解决方案,我认为这是一个具有挑战性的实现,很高兴看到你说得很好:)。

以上是关于将数组(元素组合)划分为自定义分区的所有方式的主要内容,如果未能解决你的问题,请参考以下文章

kafka自定义分区规则

为自定义数组实现迭代器

将表转换为自定义类型数组

如何将 MKMapView(或任何 UIView)裁剪为自定义形状?

将高度设置为自定义视图组

Angular-6:将字符串转换为自定义对象的数组