将数组值求和到一定总数

Sum array values up to a certain total amount

我有一个散列数组(已排序),如下所示:

testArray = [{price: 540, volume: 12},
            {price: 590, volume: 18},
            {price: 630, volume: 50}]

现在我想计算一定总体积的平均值。假设某人想购买 40 件,他希望以最便宜的方式购买。这意味着平均价格为 (540*12+590*18+630*50)/40 货币单位。

我的第一次尝试如下:

testArray.each do |priceHash|
    @priceArray << priceHash.fetch(:price)
    @volumeArray << priceHash.fetch(:volume)
end


def calculateMiddlePrice(priceArray, volumeArray, totalAmount)
result = 0

# Here some crazy wild magic happens

(0...volumeArray.count).inject(0) do |r, i| 

    if (volumeArray[0..i].inject(:+)) < totalAmount

        r += volumeArray[i]*priceArray[i]
    elsif volumeArray[0..i-1].inject(:+) < totalAmount && volumeArray[0..i].inject(:+) >= totalAmount 

        theRest = volumeArray[i] - (volumeArray[0..i].inject(:+) - totalAmount)
        r += theRest * priceArray[i]
    elsif volumeArray[0] > totalAmount

        r = totalAmount * priceArray[0]
    end

    result = r      
end
result
end

现在我什至不确定它为什么有效,但它确实有效。然而,在我眼中,这段代码绝对荒谬。

我的第二个想法是在达到总量时削减我的testArray。代码看起来更好

testAmount = 31

def returnIndexForSlice(array, amount)
 sum = 0

 array.each_index do |index|

  p sum += array[index][:volume]
  if sum >= amount
        return index+1
  end
 end
end

testArray.slice(0,returnIndexForSlice(testArray, testAmount))

不过,这感觉不太对,"rubyish" 如果您可以这么说的话。我检查了数组 class 的几乎所有方法,并尝试使用 bsearch,但是我想不出一种真正优雅的方法来解决我的问题。

我的想法是这样的:

amountToCheck = 31
array.some_method.with_index {|sum, index| return index if sum >= amountToCheck}

但是有没有这样的方法或者其他方法呢?

鉴于您的价格哈希数组:

prices = [  {price: 540, volume: 12},
            {price: 590, volume: 18},
            {price: 630, volume: 50}]

您可以通过 2 个步骤计算出您的结果。

def calc_price(prices, amount)
  order = prices.flat_map{|item| [item[:price]] * item[:volume] } #step 1      
  order.first(amount).reduce(:+)/amount #step 2
end

第 1 步:创建一个数组,其中包含每个单独的项目(如果价格未排序,则必须添加 sort_by 子句)。换句话说,将价格展开为包含 12 个 540、18 590 等的数值数组。这里使用 Ruby 的数组重复方法:[n] * 3 = [n, n, n].

第 2 步:平均前 n 个元素

结果:

calc_price(prices, 40)
=> 585