给定桶大小按体积填充容器

Filling containers by volume given a bucket size

假设我有一个包含序列号容器及其各自体积的数据集。

x <- data.frame("SN" = 1:3, "Price" = c(10,20,30), "Volume" = c(100,150,200))

SN     Price      Volume
1      10         100
2      20         150
3      30         200

我想用给定尺寸的桶装满容器。

  1. 如果容器在桶被清空之前被填满,我想 移动到下一个 SN。
  2. 如果桶先于容器清空 装满了,我想用剩下的容器开始新的一行。

bucket_size = 200 时的期望输出:

 SN     Price      Volume
    1      10         100 # max for SN 1 is 100, totally filled, bucket now = 100
    2      20         100 # max for SN 2 is 150, bucket now = 0 
    2      20          50 # fill remaining SN 2, new bucket now = 150 
    3      30         150 # max for SN 3 is 200, bucket now = 0
    3      30          50 # fill remaining in SN 3, bucket now = 150 remaining

我已经开始编码,但我的代码似乎不够通用,无法适用于任何存储桶大小。

x <- data.frame("SN" = 1:3, "Price" = c(10,20,30), "Volume" = c(100,150,200))

bucketsize <- 200
PendingBucketVolume <- bucketsize

y <- data.frame(SN = integer(),Price=numeric(),Volume=numeric(),stringsAsFactors=FALSE)

for (i in 1:nrow(x)) {
  if (x$Volume[i] <= PendingBucketVolume) {
    print(x$Volume[i])
    PendingBucketVolume <- PendingBucketVolume - x$Volume[i]
  } else {
    print(PendingBucketVolume)
    remainder <- x$Volume[i] - PendingBucketVolume
    if (remainder <= bucketsize) {
      print(remainder)
    } else {
      print(bucketsize)
      remainder <- remainder - bucketsize

    }

    if (remainder < PendingBucketVolume) {
      PendingBucketVolume <- remainder
    } else {
      PendingBucketVolume <- bucketsize
      PendingBucketVolume <- PendingBucketVolume - remainder
    }

  }
}

关于使其通用且高效的建议。

我花了太长时间试图让 if else 逻辑为此工作。行卷和桶卷的平衡过多。相反,我想我可以把所有的卷都拆开并给它们分配一个 ID,cbind 它们,然后使用 table 将它们重新组合在一起。结果可能是比 if else 方法慢得多的计算,但代码非常简单。

x <- data.frame("SN" = 1:3, "Price" = c(10,20,30), "Volume" = c(100,150,200))

allocate_buckets <- function(x, bucketsize){
  # assumption that X has the colnames
  stopifnot(colnames(x) == c("SN","Price","Volume"))
  row_num <- rep(x[,"SN"], x[,"Volume"])
  l <- length(row_num)
  bucket_num <- rep(1:ceiling(l/bucketsize), each = bucketsize)[1:l]
  out <- table(row_num, bucket_num)
  out.ind <- which(out !=0, arr.ind = T)
  return(cbind.data.frame(x[out.ind[,1],c("SN","Price")], Volume = out[out.ind]))
}

现在您可以将它用于任何(整数)卷:

allocate_buckets(x, 200)
#    SN Price Volume
#1    1    10    100
#2    2    20    100
#2.1  2    20     50
#3    3    30    150
#3.1  3    30     50

allocate_buckets(x, 67)
#    SN Price Volume
#1    1    10     67
#1.1  1    10     33
#2    2    20     34
#2.1  2    20     67
#2.2  2    20     49
#3    3    30     18
#3.1  3    30     67
#3.2  3    30     67
#3.3  3    30     48

编辑

太棒了 link 你发帖了,我离这个太近了,这是 R 版本:

x <- data.frame("SN" = 1:3, "Price" = c(10,20,30), "Volume" = c(100,150,200))
y <- data.frame(SN = integer(), Price = numeric(), Volume = numeric())
bucket <- bucketsize <- 200
vol <- numeric()
count <- 0
for(i in 1:nrow(x)){
  volume <- x[i,"Volume"]
  while(volume!=0){
    vol <- min(volume, bucket)
    print(vol)
    count <- count + 1
    y[count,] <- x[i,]
    y[count,"Volume"] <- vol
    volume <- volume - vol
    bucket <- bucket - vol
    if(bucket == 0){
      bucket <- bucketsize
    }
  }
}

编辑 2 我 运行 对这两种方法进行了微基准测试(花了一段时间),结果是与 SAS 编写的代码 t运行 相比,我原来的方法实际上看起来更快。

                     expr      min        lq      mean    median        uq       max neval
 allocate_buckets(x, 200) 312.4177  466.6347  504.2121  483.1754  516.2977  846.4529   100
            other(x, 200) 986.6495 1233.5141 1339.4219 1265.3606 1389.1158 2023.7884   100

这出乎我的意料。另一种方法的好处是它可以处理非整数值。人们可能可以通过使用 data.tables 来加速 allocate_buckets 函数,并且可以通过乘以 100 或任何使最小小数成为整数的数字,然后将结果除以来解除非整数约束100之后。