将编号分组为大小为X的最小桶数

时间:2016-02-10 16:15:54

标签: javascript arrays

寻找有关如何将数字集合分组到大小为X的最少数量的桶中的示例。

例如,如果我有这个数字数组:

var myCompartments = { 4, 6, 2, 8, 6, 3, 1, 1, 4, 2, 7, 2, 8, 3, 9 };

我希望使用这个桶大小将它们分组到桶中:

var bucketSize = 12;

我正在寻找的是一个函数或算法,它将这些函数或算法分组到与bucketSize匹配的最少数量的桶中,然后将剩余的数字(不适合)给予我自己的列表。

示例结果我希望看到:

var buckets = [ 
    { 4, 6, 2 },
    { 8, 3, 1 },
    { 6, 4, 2 },
    { 9, 3 }
];

var leftovers = {1, 7, 2, 8 };

如果它可以输出类似于样本结果那么好。 "遗留在"中的项目数量最少列表,越多越好。

到目前为止我只是简单地循环收集并在有空间的情况下添加到存储桶,如果没有空间则创建一个新存储桶。这是低效的,最终会有很多部分满满的存储桶。我使用的是angularJS,因此这里使用了一些快捷方法:

var bucketSize = 12;
var buckets = [
    { remainingCapacity: bucketSize, items: [] }
];
var myCompartments = [
    { isAssigned: false, size: 4 },   
    { isAssigned: false, size: 6 },   
    { isAssigned: false, size: 2 },   
    { isAssigned: false, size: 8 },   
    { isAssigned: false, size: 6 },   
    { isAssigned: false, size: 3 },   
    { isAssigned: false, size: 1 },   
    { isAssigned: false, size: 1 },   
    { isAssigned: false, size: 4 },   
    { isAssigned: false, size: 2 },   
    { isAssigned: false, size: 7 },   
    { isAssigned: false, size: 2 },   
    { isAssigned: false, size: 8 },
    { isAssigned: false, size: 3 },
    { isAssigned: false, size: 9 }
];

myCompartments.forEach(function(compartment) {
    buckets.forEach(function(bucket) {
        if (bucket.remainingCapacity >= compartment.size && !compartment.isAssigned) {
            bucket.remainingCapacity -= compartment.size;
            compartment.isAssigned = true;
            bucket.items.push(compartment);
        }
    });

    // if compartment still not assigned, add to a new bucket
    if (!compartment.isAssigned && bucketSize >= compartment.size) {
        compartment.isAssigned = true;
        var remainingCapacity = bucketSize - compartment.size;
        var newBucket = { remainingCapacity: remainingCapacity, items: [] };
        newBucket.items.push(compartment);
        buckets.push(newBucket);
    }
});

编辑 - 我创建了一个plunker,用于输出已创建的存储桶以进行调试

1 个答案:

答案 0 :(得分:0)

这不太好但是有效。

它循环遍历数据多次,每次洗牌都是为了找到一个更好的顺序,将项目分组到特定大小的桶中。

plunker

$(function() {

  var bucketSize = 12;  
  var buckets = [{
    remainingCapacity: bucketSize,
    pieces: []
  }];

  var pieces = [
      { isAssigned: false, size: 4 },     
      { isAssigned: false, size: 6 },   
      { isAssigned: false, size: 2 },   
      { isAssigned: false, size: 8 },   
      { isAssigned: false, size: 6 },   
      { isAssigned: false, size: 3 },   
      { isAssigned: false, size: 1 },   
      { isAssigned: false, size: 1 },   
      { isAssigned: false, size: 4 },   
      { isAssigned: false, size: 2 },   
      { isAssigned: false, size: 7 },   
      { isAssigned: false, size: 2 },   
      { isAssigned: false, size: 8 },
      { isAssigned: false, size: 3 },
      { isAssigned: false, size: 9 }
  ];

  var unassignedCount = pieces.length;

  var count = 1000;

  while (count--) {

    shuffle(pieces);  

    var p = pieces.length;
    var b = 0;

    while (p--) {

      var piece = pieces[p];
      b = buckets.length;

      while (b--) {

        var bucket = buckets[b];

        // add to bucket if there is room and piece is not assigned
        if (bucket.remainingCapacity >= piece.size && !piece.isAssigned) {
          bucket.remainingCapacity -= piece.size;
          piece.isAssigned = true;
          bucket.pieces.push(piece);
        }
      }

      // if not assigned and not bigger than bucketSize, add to new bucket
      if (!piece.isAssigned && piece.size <= bucketSize) {
        var remainingCapacity = bucketSize - piece.size;
        var newBucket = {
          remainingCapacity: remainingCapacity,
          pieces: []
        };
        newBucket.pieces.push(piece);
        buckets.push(newBucket);
      }

      pieces.splice(p, 1);

    }

    b = buckets.length;

    while (b--) {
      var bucket = buckets[b];
      if (bucket.remainingCapacity > 0) {
        p = bucket.pieces.length;
        while (p--) {
          var piece = bucket.pieces[p];
          piece.isAssigned = false;
          pieces.push(piece);
          bucket.pieces.splice(p, 1);
        }
        buckets.splice(b, 1);
      }

    }  

    unassignedCount = pieces.length;

  }


  function shuffle(array) {
    var currentIndex = array.length,
      temporaryValue, randomIndex;

    // While there remain elements to shuffle...
    while (0 !== currentIndex) {

      // Pick a remaining element...
      randomIndex = Math.floor(Math.random() * currentIndex);
      currentIndex -= 1;

      // And swap it with the current element.
      temporaryValue = array[currentIndex];
      array[currentIndex] = array[randomIndex];
      array[randomIndex] = temporaryValue;
    }

    return array;
  }

  document.write('number of buckets: ' + buckets.length + '<br><br>');
  document.write('number of remaining pieces: ' + unassignedCount + '<br>    <br>');
  buckets.forEach(function(bucket) {
    document.write('bucket:<br>');
    document.write('remaining capacity: ' + bucket.remainingCapacity + '<br>');
    document.write('items:<br>');
    bucket.pieces.forEach(function(piece) {
      document.write('size: ' + piece.size + '<br>');
    });
    document.write('<br>');
  });

  document.write('<br>leftovers: ');
  pieces.forEach(function(piece) {
    if (!piece.isAssigned) {
      document.write(piece.size + ', ');
    }
  });

});

如果其他人有更优雅的解决方案,我会非常有兴趣看看你想出了什么!感谢。