【问题标题】:Output each combination of an array of numbers with javascript用javascript输出数字数组的每个组合
【发布时间】:2011-05-02 22:38:36
【问题描述】:

我在一个数组中有几个数字

var numArr = [1, 3, 5, 9];

我想循环遍历该数组并将每个唯一的 3 个数字组合相乘,如下所示:

1 * 3 * 5 = 
1 * 3 * 9 = 
1 * 5 * 9 = 
3 * 5 * 9 =

然后返回所有计算的数组

var ansArr = [15,27,45,135];

谁有一个优雅的解决方案?提前致谢。

【问题讨论】:

  • 在标题中您要求排列,但在正文中您提到组合。它是哪一个? (我猜是组合,因为乘法是可交换的。)
  • @DaveKingsnorth 注意:数组中有字符串,而不是数字。
  • @Sime Vidas - 这是一个错误,它们应该是数字而不是字符串
  • @DaveKingsnorth 数组中的数字是否不同?
  • @Sime Vidas - 并非总是如此,数组中可能有重复的数字

标签: javascript combinations


【解决方案1】:

生成组合的通用算法如下:

function combinations(numArr, choose, callback) {
    var n = numArr.length;
    var c = [];
    var inner = function(start, choose_) {
        if (choose_ == 0) {
            callback(c);
        } else {
            for (var i = start; i <= n - choose_; ++i) {
                c.push(numArr[i]);
                inner(i + 1, choose_ - 1);
                c.pop();
            }
        }
    }
    inner(0, choose);
}

在你的情况下,你可以这样称呼它:

function product(arr) {
    p = 1;
    for (var i in arr) {
        p *= arr[i];
    }
    return p;
}

var ansArr = [];

combinations(
    [1, 3, 5, 7, 9, 11], 3,
    function output(arr) {
        ansArr.push(product(arr));
    });

document.write(ansArr);

...对于给定的输入,产生这个:

15,21,27,33,35,45,55,63,77,99,105,135,165,189,231,297,315,385,495,693

【讨论】:

    【解决方案2】:

    我认为这应该可行:

    var a = [1, 3, 5, 9];
    var l = a.length;
    var r = [];
    for (var i = 0; i < l; ++i) {
      for (var j = i + 1; j < l; ++j) {
        for (var k = j + 1; k < l; ++k) {
          r.push(a[i] * a[j] * a[k]);
        }
      }
    }
    

    编辑

    只是为了我自己的启迪,我想出了一个使用循环而不是递归的通用解决方案。明显的缺点是它更长,因此加载或阅读速度更慢。另一方面(至少在我机器上的 Firefox 上)它的运行速度大约是递归版本的两倍。但是,如果您要查找大型集合的组合,或者在同一页面上多次查找组合,我只会推荐它。无论如何,如果有人感兴趣,这就是我想出的。

    function combos(superset, size) {
      var result = [];
      if (superset.length < size) {return result;}
      var done = false;
      var current_combo, distance_back, new_last_index;
      var indexes = [];
      var indexes_last = size - 1;
      var superset_last = superset.length - 1;
    
      // initialize indexes to start with leftmost combo
      for (var i = 0; i < size; ++i) {
        indexes[i] = i;
      }
    
      while (!done) {
        current_combo = [];
        for (i = 0; i < size; ++i) {
          current_combo.push(superset[indexes[i]]);
        }
        result.push(current_combo);
        if (indexes[indexes_last] == superset_last) {
          done = true;
          for (i = indexes_last - 1; i > -1 ; --i) {
            distance_back = indexes_last - i;
            new_last_index = indexes[indexes_last - distance_back] + distance_back + 1;
            if (new_last_index <= superset_last) {
              indexes[indexes_last] = new_last_index;
              done = false;
              break;
            }
          }
          if (!done) {
            ++indexes[indexes_last - distance_back];
            --distance_back;
            for (; distance_back; --distance_back) {
              indexes[indexes_last - distance_back] = indexes[indexes_last - distance_back - 1] + 1;
            }
          }
        }
        else {++indexes[indexes_last]}
      }
      return result;
    }
    
    function products(sets) {
      var result = [];
      var len = sets.length;
      var product;
      for (var i = 0; i < len; ++i) {
        product = 1;
        inner_len = sets[i].length;
        for (var j = 0; j < inner_len; ++j) {
          product *= sets[i][j];
        }
        result.push(product);
      }
      return result;
    }
    
    console.log(products(combos([1, 3, 5, 7, 9, 11], 3)));
    

    【讨论】:

    • 如果我想获得所有 2 个数字组合或 5 个数字组合(如果我有一个更长的数组),有没有可以将该值指定为变量的解决方案(我说的是指定组合的长度)。
    • @DaveKingsnorth 如果你想改变它,那么我的解决方案太具体了。请参阅 Marcelo 更通用的解决方案。
    • 您的解决方案实际上回答了我最初的问题,但马塞洛的正是我所追求的。感谢您的意见。
    【解决方案3】:

    当您需要从 n 个数字中选择 k 个数字时执行此操作的递归函数。没有测试过。查找是否有任何错误并纠正它:-)

    var result = [];
    
    foo(arr, 0, 1, k, n); // initial call
    
    function foo(arr, s, mul, k, n) {
        if (k == 1) {
            result.push(mul);
            return;
        }
    
        var i;
        for (i=s; i<=n-k; i++) {
            foo(arr, i+1, mul*arr[i], k-1, n-i-1);
        }
    }
    

    这是一个递归函数。

    1. 第一个参数是数组arr

    2. 第二个参数是整数s。每次调用都会计算从索引s 开始的部分数组的值。我递归地增加s,因此每个调用的数组递归地变小。

    3. 第三个参数是递归计算并在递归调用中传递的值。当k 变为 1 时,它被添加到结果数组中。

    4. k 在所需的组合大小中。它递归减少,当变为 1 时,输出附加到结果数组中。

    5. n 是数组 arr 的大小。其实n = arr.length

    【讨论】:

    • @Niraj - 你能解释一下每个参数是什么吗?
    • 这是一个递归函数。 1) 第一个参数是数组 arr。 2) 第二个参数是整数 s。每次调用都会计算从索引 s 开始的部分数组的值。递归地我正在增加 s ,因此每个调用的数组递归地变小。 3) 第三个参数是递归计算并在递归调用中传递的值。当 k 变为 1 时,它被添加到结果数组中。 4) k 中所需的组合大小。它递归减少,当变为 1 时,输出附加到结果数组中。 5) n 是数组 arr 的大小。实际上 n = arr.length
    • 这就是我的想法,但我仍然在某个地方犯了错误。我这样调用函数: var arr = [2, 1, 4, 1, 6]; foo(arr, 0, 1, 4, 5);并像这样输出: document.write(result);我做错了什么?
    【解决方案4】:
    var create3Combi = function(array) {
        var result = [];
        array.map(function(item1, index1) {
            array.map(function(item2, index2) {
                for (var i = index2 + 1; i < array.length; i++) {
                    var item3 = array[i];
                    if (item1 === item2 || item1 === item3 || item2 === item3 || index2 < index1) {
                        continue;
                    }
                    result.push([item1, item2, item3]);
                }
            });
        });
    
        return result;
    };
    
    var multiplyCombi = function(array) {
        var multiply = function(a, b){
            return a * b;
        };
    
        var result = array.map(function(item, index) {
            return item.reduce(multiply);
        });
    
        return result;
    }
    
    var numArr = [1, 3, 5, 9];
    
    //  create unique 3 number combination
    var combi = create3Combi(numArr); //[[1,3,5],[1,3,9],[1,5,9],[3,5,9]]
    
    // multiply every combination
    var multiplyResult = multiplyCombi(combi); //[15,27,45,135];
    

    【讨论】:

      【解决方案5】:

      https://github.com/dankogai/js-combinatorics

      找到这个库。经测试可以正常工作。以下来自图书馆文档:

      var Combinatorics = require('js-combinatorics');
      var cmb = Combinatorics.combination(['a','b','c','d'], 2);
      while(a = cmb.next()) console.log(a);
      //  ["a", "b"]
      //  ["a", "c"]
      //  ["a", "d"]
      //  ["b", "c"]
      //  ["b", "d"]
      //  ["c", "d"]
      

      【讨论】:

        【解决方案6】:

        使用节点,您可以使用库非常轻松地做到这一点。首先使用 npm 安装bit-twiddle

        npm install bit-twiddle
        

        然后你可以像这样在你的代码中使用它:

        //Assume n is the size of the set and k is the size of the combination
        var nextCombination = require("bit-twiddle").nextCombination
        for(var x=(1<<(k+1))-1; x<1<<n; x=nextCombination(x)) {
           console.log(x.toString(2))
        }
        

        变量x 是一个位向量,如果组合中包含ith 元素,则设置位i

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2010-12-21
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多