生成数字数组的有效数字组合

时间:2017-12-26 11:13:36

标签: javascript combinations combinatorics

我正在尝试从数组中生成所有有效的数字组合。我们假设我们有以下内容:

let arr = [1, 2, 9, 4, 7];

我们需要输出这样的东西:

1 2 9 4 7
1 2 9 47
1 2 94 7
1 2 947
1 29 4 7
1 29 47
1 294 7
1 2947
12 9 4 7
12 9 47
12 94 7
12 947
129 4 7
129 47
1294 7
12947

无效的数字是91,497,72等等。

我尝试了这个,但我对结果不满意:

const combination = (arr) => {

  let i, j, temp;
  let result = [];
  let arrLen = arr.length;
  let power = Math.pow;
  let combinations = power(2, arrLen);

  for (i = 0; i < combinations; i += 1) {
    temp = '';

    for (j = 0; j < arrLen; j++) {
      if ((i & power(2, j))) {
        temp += arr[j];
      }
    }
    result.push(temp);
  }
  return result;
}

const result = combination([1, 2, 9, 4, 7]);
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }

有什么想法吗?

4 个答案:

答案 0 :(得分:3)

所以你需要迭代&#34;空间&#34;的所有组合。和#34;不是空间&#34;在所有数字之间。对于n项,会有n - 1个空格和2 ** (n - 1)个不同的列表。

所以你可以做这样的事情来获得所有可能的列表:

&#13;
&#13;
const combination = arr => {
    const len = arr.length;
    const n = Math.pow(2, len - 1);
    const combinations = [];
    for (let i = 0; i < n; i++) {
        let this_combination = [arr[0]];
        for (let j = 1; j < len; j++) {
           if (i & Math.pow(2, j - 1)) {
               // If the jth bit is on, no space. Append to the last element.
               const last_index = this_combination.length - 1;
               this_combination[last_index] = +(this_combination[last_index] + '' + arr[j]);
           } else {
               // Otherwise create a new list item.
               this_combination.push(arr[j]);
           }
        }
        // Consider making this function a generator and making this a yield.
        combinations.push(this_combination);
    }
    return combinations;
}

const result = combination([1, 2, 9, 4, 7]);
console.log(result.map(line => line.join(' ')).join('\n'));
&#13;
.as-console-wrapper { max-height: 100% !important; top: 0; }
&#13;
&#13;
&#13;

如果你想要每个单独的项目,对于数组中的每个项目,将它与其他项目合并,然后只是下一个项目,然后是接下来的两个项目等,直到结束:

&#13;
&#13;
const combination = arr => {
    const len = arr.length;
    const combinations = [];
    for (let i = 0; i < len; i++) {
        let item = arr[i];
        combinations.push(item);
        for (let j = i + 1; j < len; j++) {
            item = +(item + '' + arr[j]);
            combinations.push(item);
        }
    }
    return combinations;
}

const result = combination([1, 2, 9, 4, 7]);
console.log(result.join('\n'));
&#13;
.as-console-wrapper { max-height: 100% !important; top: 0; }
&#13;
&#13;
&#13;

答案 1 :(得分:3)

此代码可以满足您的需求:

&#13;
&#13;
const arr = [1, 2, 9, 4, 7],
  result = Array.from({length: 2 ** (arr.length - 1)}, (_, index) => index.toString(2).padStart(arr.length - 1, "0"))
    .map((binary) => JSON.parse("[" + arr.map((num, position) => num + (Number(binary[position]) ? "," : "")).join("") + "]"));

console.log(result);
&#13;
.as-console-wrapper { max-height: 100% !important; top: 0; }
&#13;
&#13;
&#13;

结果是:

[
  [12947],
  [1294, 7],
  [129, 47],
  [129, 4, 7],
  [12, 947],
  [12, 94, 7],
  [12, 9, 47],
  [12, 9, 4, 7],
  [1, 2947],
  [1, 294, 7],
  [1, 29, 47],
  [1, 29, 4, 7],
  [1, 2, 947],
  [1, 2, 94, 7],
  [1, 2, 9, 47],
  [1, 2, 9, 4, 7]
]

假设,预期结果不依赖于顺序,空格表示二进制模式:

12947     => 0000
1294 7    => 0001
129 47    => 0010
…
1 29 47   => 1010
…
1 2 9 4 7 => 1111

我们可以将这个模式与我们转换为二进制字符串的计数器一起使用。我们还用0填充该字符串,因此它总是保持4位数字:

index.toString(2).padStart(arr.length - 1, "0")

对于arr中的 n 数字,正好有2个 n - 1 组合,因此我们使用:

{length: 2 ** (arr.length - 1)}

这是一个length属性为2 arr.length - 1 的对象。

我们将这些内容组合成Array.from调用,该调用接受两个参数:

  • 要变成数组的对象
  • 映射每个插槽的功能

将具有length属性的对象转换为数组意味着我们创建了一个length多个插槽的数组。

映射函数接受插槽的索引作为第二个参数。我们只使用索引 - 作为二进制数的计数器。

所以,最后这个表达方式:

Array.from({length: 2 ** (arr.length - 1)}, (_, index) => index.toString(2).padStart(arr.length - 1, "0"))

评估以下数组:

[
  "0000",
  "0001",
  "0010",
  "0011",
  "0100",
  "0101",
  "0110",
  "0111",
  "1000",
  "1001",
  "1010",
  "1011",
  "1100",
  "1101",
  "1110",
  "1111"
]

我们需要进一步将其映射到最终结果:

.map((binary) => …)

对于每个数组元素,binary是上面数组中的二进制字符串之一。

为了转向,对"0110"之类的内容"12,9,47" map,我们需要arr超过num。来自arr的每个数字,都应该position binary1 position arr.map((num, position) => num + (Number(binary[position]) ? "," : "")).join("") 位于(Number(binary[position]) ? "," : "")

binary

表达式0","评估为指定位置的数字。如果它是 truthy ,即除0以外的任何内容,则评估为"",如果它是 falsy ,即["1", "2,", "9,", "4", "7"],则评估为"12,9,47"

因此中间数组看起来像JSON.parse("[" +。所有这些都联合起来+ "]")

然后,[12, 9, 47] ... 2 ** (arr.length - 1)将其视为一个数组进行处理和解析,因此变为Math.pow(2, arr.length - 1)。由于这些步骤适用于每个二进制字符串,因此最终会得到最终结果。

    如果不支持ECMAScript 7,则
  • {length: 2 ** (arr.length - 1)}可以替换为new Array(2 ** (arr.length - 1))
  • (Number(binary[position]) ? "," : "")可以替换为["", ","][Number(binary[position])]
  • MariaDB可以由tmp替换。在这种情况下,评估的数字将用作临时数组的索引。

答案 2 :(得分:1)

您可以通过迭代数组并插入空格来进行递归方法,并使用递增的索引分叉调用相同的函数。

&#13;
&#13;
function combine(array) {
    function fork(i, p) {
        if (i === array.length) {
            result.push(p);
            return;
        }
        fork(i + 1, p + ' ' + array[i]);
        fork(i + 1, p + array[i]);
    }
    var result = [];
    fork(1, array[0].toString());
    return result;
}

console.log(combine([1, 2, 9, 4, 7]));
&#13;
.as-console-wrapper { max-height: 100% !important; top: 0; }
&#13;
&#13;
&#13;

答案 3 :(得分:0)

你可以使用下面的代码,使用3指针,

  1. 第一个指针将第0个位置打印到光标位置。
  2. 第二个指针在每次迭代中将光标打印到不同位置。
  3. 第3个指针将光标位置打印到最后位置。
  4. let arr = [1, 2, 9, 4, 7];
    console.log(arr.join(','));
    for(let diff=2;diff<=arr.length;diff++){
      for(i=0,j=diff;arr.length>=i+diff;j++,i++){
        var temp = [];
        if(i>0)
          temp.push(arr.slice(0,i).join(','));
        temp.push(arr.slice(i,j).join(''));
        if(j<arr.length)
          temp.push(arr.slice(j,arr.length).join(','));
        console.log(temp.join(','));
      }
    }