Javascript - 生成适合固定总和

时间:2015-09-06 21:32:29

标签: javascript underscore.js lodash

我收集了一些文件,每个文件都有一个条目" weight"和"点"。 然后是一个随机从该集合中获取条目的方法。

方法内部是一个整数变量" pointsTotal",文档点应按权重分配。 到目前为止,问题是: 如果积分在没有剩余的情况下是不可分的,则赢得的总和不再是200。

示例:

enter image description here

此外,我想以5的步长舍入值,但是当我尝试总和超过给定的pointsTotal。

舍入示例:

enter image description here

代码示例



collectionP = [{
  name: "pi",
  weight: 2,
  points: 0
}, {
  name: "pe",
  weight: 3,
  points: 0
}, {
  name: "pa",
  weight: 1,
  points: 0
}, {
  name: "po",
  weight: 2,
  points: 0
}, {
  name: "pu",
  weight: 3,
  points: 0
}];

round5 = function(number) {
  return Math.ceil(number / 5) * 5;
};


randomizePartition = function(collection) {

  var partition = [];
  var sumWeight = 0;
  var pointsTotal = 200;

  var sumPoints = 0;

  var randomLength = _.random(1, collection.length);
  var randomArray = _.sample(_.shuffle(collection), randomLength);

  _.forEach(randomArray, function(document) {
    sumWeight += document.weight;
  });
  _.forEach(randomArray, function(document) {
    document.points = round5((document.weight / sumWeight) * pointsTotal);
    sumPoints += document.points;
    partition.push(document);
    console.log(document.name + ": " + document.points);
  });
  console.log("Total Points: " + sumPoints);

};


randomizePartition(collectionP);

<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/3.10.1/lodash.min.js"></script>
&#13;
&#13;
&#13;

目标

我希望每个文档的点数能够无缝地符合200,取决于它们的重量并将其舍入为5。

提前感谢您的帮助! VIN

2 个答案:

答案 0 :(得分:1)

通过根据结果更改总和和总计,将原始值和舍入值之间的差值反馈。这样,每个数字都是根据舍入后的前一个数字后面的内容计算的,而不是舍入前的初始计算。

&#13;
&#13;
collectionP = [{
  name: "pi",
  weight: 2,
  points: 0
}, {
  name: "pe",
  weight: 3,
  points: 0
}, {
  name: "pa",
  weight: 1,
  points: 0
}, {
  name: "po",
  weight: 2,
  points: 0
}, {
  name: "pu",
  weight: 3,
  points: 0
}];

round5 = function(number) {
  return Math.ceil(number / 5) * 5;
};


randomizePartition = function(collection) {

  var partition = [];
  var sumWeight = 0;
  var pointsTotal = 200;

  var sumPoints = 0;

  var randomLength = _.random(1, collection.length);
  var randomArray = _.sample(_.shuffle(collection), randomLength);

  _.forEach(randomArray, function(doc) {
    sumWeight += doc.weight;
  });
  _.forEach(randomArray, function(doc) {
    doc.points = round5((doc.weight / sumWeight) * pointsTotal);
    sumPoints += doc.points;
    partition.push(doc);
    console.log(doc.name + ": " + doc.points);
    sumWeight -= doc.weight;
    pointsTotal -= doc.points;
  });
  console.log("Total Points: " + sumPoints);

};


randomizePartition(collectionP);
&#13;
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/3.10.1/lodash.min.js"></script>
&#13;
&#13;
&#13;

答案 1 :(得分:1)

您可以使用Big Decimal库。它在处理浮点运算方面做得非常好。您的代码可能如下所示: -

    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">

<html>
<head>
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/3.10.1/lodash.min.js"></script>


<script src='https://raw.githubusercontent.com/MikeMcl/big.js/master/big.js'></script>


</head>
<body>
<script>
collectionP = [{
  name: "pi",
  weight: 0.000000000000000000000000000000000000000000000001,
  points: 0
}, {
  name: "pe",
  weight: 5.99999999999999999999999999999999999999999999999,
  points: 0
}, {
  name: "pa",
  weight: 6.99999999999999999999999999999999999999999999999,
  points: 0
}, {
  name: "po",
  weight: 2.99999999999999999999999999999999999999999999999,
  points: 0
}, {
  name: "pu",
  weight: 3.99999999999999999999999999999999999999999999999,
  points: 0
}];

round5 = function(number) {
  return Math.round(number );
};


randomizePartition = function(collection) {
Big.DP = 10
Big.RM = 1

  var partition = [];
  var sumWeight = new Big ("0");
  var pointsTotal = new Big ("200");

  var sumPoints = new Big("0");

  var randomLength = _.random(1, collection.length);
  var randomArray = _.sample(_.shuffle(collection), randomLength);

  _.forEach(randomArray, function(document) {
    sumWeight = sumWeight.plus(document.weight);
  });

    console.log ("sumWeight = " + sumWeight);
  _.forEach(randomArray, function(document) {
    document.points = new Big (document.weight / sumWeight).times (pointsTotal);
    sumPoints = sumPoints.plus(document.points);
    partition.push(document);
    console.log(document.name + ": " + document.points);
  });
    Big.DP = 0;
  console.log("Total Points: " + sumPoints.round(0));

};


randomizePartition(collectionP);
</script>
</body>
</html>