量化一个数组,使量化值的子集仍然被一致地量化
Quantizing an array so that a subset of quantized values is still consistently quantized
给定一个 int
数组,我想量化每个值,使量化值之和为 100。每个量化值也应该是整数。这在整个数组被量化时有效,但是当量化值的子集相加时,它不会相对于其余值保持量化。
例如,值44、40、7、2、0、0被量化为47、43、8、2、0、0(其和为100)。如果取最后 4 个量化值,则总和为 53,这与第一个值一致(即 47 + 53 = 100)。
但对于值 78、7、7、1、0、0,最后 4 个量化值 (8、8、1、0、0) 的总和为 17。第一个量化值是 84,即添加到 17 时不等于 100。显然,这是由于四舍五入的原因。有没有办法调整舍入以使子集仍然一致?
这里是 Ruby 代码:
class Quantize
def initialize(array)
@array = array.map { |a| a.to_i }
end
def values
@array.map { |a| quantize(a) }
end
def sub_total(i, j)
@array[i..j].map { |a| quantize(a) }.reduce(:+)
end
private
def quantize(val)
(val * 100.0 / total).round(0)
end
def total
@array.reduce(:+)
end
end
以及(失败的)测试:
require 'quantize'
describe Quantize do
context 'first example' do
let(:subject) { described_class.new([44, 40, 7, 2, 0, 0]) }
context '#values' do
it 'quantizes array to add up to 100' do
expect(subject.values).to eq([47, 43, 8, 2, 0, 0])
end
end
context '#sub_total' do
it 'adds a subset of array' do
expect(subject.sub_total(1, 5)).to eq(53)
end
end
end
context 'second example' do
let(:subject) { described_class.new([78, 7, 7, 1, 0, 0]) }
context '#values' do
it 'quantizes array to add up to 100' do
expect(subject.values).to eq([84, 8, 8, 1, 0, 0])
end
end
context '#sub_total' do
it 'adds a subset of array' do
expect(subject.sub_total(1, 5)).to eq(16)
end
end
end
end
如问题评论中所述,量化例程未正确执行:第二个示例 [78, 7, 7, 1, 0, 0]
被量化为 [84, 8, 8, 1, 0, 0]
— 加到 101 而不是 100。
这是一种可以产生正确结果的方法:
def quantize(array, value)
quantized = array.map(&:to_i)
total = array.reduce(:+)
remainder = value - total
index = 0
if remainder > 0
while remainder > 0
quantized[index] += 1
remainder -= 1
index = (index + 1) % quantized.length
end
else
while remainder < 0
quantized[index] -= 1
remainder += 1
index = (index + 1) % quantized.length
end
end
quantized
end
如问题所述,这解决了您的问题。麻烦的结果变成 [80, 8, 8, 2, 1, 1]
,它加到 100 并保持您描述的子集关系。当然,该解决方案可以提高性能 — 但它的优点是可以工作并且非常简单易懂。
给定一个 int
数组,我想量化每个值,使量化值之和为 100。每个量化值也应该是整数。这在整个数组被量化时有效,但是当量化值的子集相加时,它不会相对于其余值保持量化。
例如,值44、40、7、2、0、0被量化为47、43、8、2、0、0(其和为100)。如果取最后 4 个量化值,则总和为 53,这与第一个值一致(即 47 + 53 = 100)。
但对于值 78、7、7、1、0、0,最后 4 个量化值 (8、8、1、0、0) 的总和为 17。第一个量化值是 84,即添加到 17 时不等于 100。显然,这是由于四舍五入的原因。有没有办法调整舍入以使子集仍然一致?
这里是 Ruby 代码:
class Quantize
def initialize(array)
@array = array.map { |a| a.to_i }
end
def values
@array.map { |a| quantize(a) }
end
def sub_total(i, j)
@array[i..j].map { |a| quantize(a) }.reduce(:+)
end
private
def quantize(val)
(val * 100.0 / total).round(0)
end
def total
@array.reduce(:+)
end
end
以及(失败的)测试:
require 'quantize'
describe Quantize do
context 'first example' do
let(:subject) { described_class.new([44, 40, 7, 2, 0, 0]) }
context '#values' do
it 'quantizes array to add up to 100' do
expect(subject.values).to eq([47, 43, 8, 2, 0, 0])
end
end
context '#sub_total' do
it 'adds a subset of array' do
expect(subject.sub_total(1, 5)).to eq(53)
end
end
end
context 'second example' do
let(:subject) { described_class.new([78, 7, 7, 1, 0, 0]) }
context '#values' do
it 'quantizes array to add up to 100' do
expect(subject.values).to eq([84, 8, 8, 1, 0, 0])
end
end
context '#sub_total' do
it 'adds a subset of array' do
expect(subject.sub_total(1, 5)).to eq(16)
end
end
end
end
如问题评论中所述,量化例程未正确执行:第二个示例 [78, 7, 7, 1, 0, 0]
被量化为 [84, 8, 8, 1, 0, 0]
— 加到 101 而不是 100。
这是一种可以产生正确结果的方法:
def quantize(array, value)
quantized = array.map(&:to_i)
total = array.reduce(:+)
remainder = value - total
index = 0
if remainder > 0
while remainder > 0
quantized[index] += 1
remainder -= 1
index = (index + 1) % quantized.length
end
else
while remainder < 0
quantized[index] -= 1
remainder += 1
index = (index + 1) % quantized.length
end
end
quantized
end
如问题所述,这解决了您的问题。麻烦的结果变成 [80, 8, 8, 2, 1, 1]
,它加到 100 并保持您描述的子集关系。当然,该解决方案可以提高性能 — 但它的优点是可以工作并且非常简单易懂。