通过约束每个可能性来迭代选项

时间:2017-08-26 19:44:39

标签: javascript arrays algorithm sorting vector

我有一个问题,我需要以编程方式迭代许多可能性。

让我举个例子,因为它会更容易理解。

我有一个向量(或简单的数组) [0.4,0.2,0.3,0.1] 其中每个值介于0和1之间步长为0.1 ,其总和必须 1

我也有传递此数组的函数,它返回一个数字。

目标是尝试将所有可能的值组合到数组中,并保持函数给出尽可能最小的值。

我试图找到一种简单的方法来迭代可能的解决方案,但无法达到我可以轻松编码的东西。

2 个答案:

答案 0 :(得分:0)

首先,您需要一个能够计算数组所有可能排列的函数。

这是(我从here获取):

function permutations(list) {
  if (list.length <= 1) {
    return list.slice();
  }

  var result = [];
  var rest;
  var current;
  var permutationsRest;
  var i, j;

  for (i = 0; i < list.length; i++) {
    rest = list.slice(); // make a copy of list
    current = rest.splice(i, 1);
    permutationsRest = permutations(rest);
    for (j = 0; j < permutationsRest.length; j++) {
      result.push(current.concat(permutationsRest[j]));
    }
  }

  return result;
}

接下来,使您的函数返回给定数组的数字。为了举个例子,我做了我的:

function calculate(array) {
  var i;
  var score = 0;
  for (i = 0; i < array.length; i++) {
    score = array[i] * (i + 1);
  }
  return score;
}

然后在所有排列上应用此函数,同时存储最佳结果。

var permutations = permutations([0.4, 0.2, 0.3, 0.1]);
var score;
var bestScore = Number.MAX_VALUE; // as you stated that lower the score is, better it is, so MAX_VALUE would be the worst score possible
var bestPermutation;
var i;

for (i = 0; i < permutations.length; i++) {
  score = calculate(permutations[i]);
  if (score < bestScore) { // lower is best
    bestScore = score;
    bestPermutation = permutations[i];
  }
}

console.log(bestScore);
console.log(bestPermutation);
// prints "[0.4, 0.2, 0.3, 0.1]"
  

我希望排列为:[0.0,1.0] [0.1,0.9] [0.2,0.8] [0.3,   0.7] [0.4,0.6] [0.5,0.5] [0.6,0.4] [0.7,0.3] [0.8,0.2] [0.9,0.1] [1.0,0.0]注意在每个排列中,总和是1。

以下函数将为给定大小创建任何可能的排列,其中sum将等于1并步进到0.1。 我使用ES6更简洁,告诉我你是否需要旧的浏览器支持。

请注意,为了避免奇怪的浮点值(例如0.7999999999999998),我使用从010的整数,我在返回结果数组之前进行除法。

function createVector(size) {
  return (function recursive(permutations) {
    if (permutations[0].length === size) {
      // end of recursive, so map 0-10 values to 0.0-1.0
      return permutations.filter(t => t.reduce((a, b) => a + b, 0) === 10)
                         .map(t => t.map(i => i / 10));
    }

    // calculate each permutation which sum <= 10
    const newPermutations = [];
    for (let i = 0; i <= 10; i++) {
      permutations.filter(permutation => permutation.reduce((a, b) => a + b, i) <= 10)
                  .forEach(permutation => newPermutations.push([i].concat(permutation)));
    }

    return recursive(newPermutations);
  }([[]])); // start with empty array []
}

const result = createVector(2);
console.log(result);
// [[0,1], [0.1,0.9], [0.2,0.8], [0.3,0.7], [0.4,0.6], [0.5,0.5], [0.6,0.4], [0.7,0.3], [0.8,0.2], [0.9,0.1], [1,0]]
  

我想在计算尺寸&gt;的矢量时遇到一些限制; 4(它只是堆栈溢出)

为避免堆栈溢出错误,我制作了一个迭代版本,因此不涉及任何功能。根据这个benchmark,它快2到3倍,而且由于代码有点长,你可以在下面的小提琴中找到它:
https://jsfiddle.net/7v5w7zpy/

答案 1 :(得分:0)

假设,通过组合,你意味着与至少两个元素的组合并且知道所有元素彼此相距至少0.1步(这意味着没有欺骗)你可以找到最小值和第二个最小值并添加它们

&#13;
&#13;
function getMinSum(a){
  var min = Math.min(...a);
  return min + a.reduce((p,c) => p > min && c > min ? p < c ? p
                                                            : c
                                                    : p === min ? c
                                                                : p);
}

var arr = [0.4, 0.2, 0.3, 0.1];
console.log(getMinSum(arr));
&#13;
&#13;
&#13;