小数因子的降尺度数组

Downscale array for decimal factor

本文关键字:数组 小数      更新时间:2023-10-16

有没有有效的方法按十进制因子缩小数组中元素的数量?

我想按特定因素缩小一个数组中的元素。

例:如果我有 10 个元素并且需要按系数 2 缩小。

1 2 3 4 5 6 7 8 9 10
scaled to
1.5 3.5 5.5 7.5 9.5

将 2 分组 2 并使用算术平均值。

我的问题是,如果我需要将包含 10 个元素的数组缩小到 6 个元素怎么办?理论上,我应该对 1.6 个元素进行分组并找到它们的算术平均值,但如何做到这一点呢?

在提出解决方案之前,让我们以更正式的方式定义"缩小"。我建议这个定义:

缩小大小从a[N]数组开始,并生成一个数组b[M]以便满足以下条件:

  1. M <= N - 否则它将扩大规模,而不是缩小规模
  2. SUM(b) = (M/N) * SUM(a) - 总和与元素数成比例减少
  3. a元素按照它们在a中出现的顺序参与b的计算

让我们考虑一下您将1, 2, 3, 4, 5, 6, 7, 8, 9, 10缩小到六个元素的示例。数组的总数为 55,因此新阵列的总数将为 (6/10)*55 = 33 。我们可以通过两个步骤实现这个总数:

  • 遍历数组a对其元素求和,直到我们到达N/M分数的整数部分(根据上面的规则 1,它必须是不正确的分数)
  • 假设a[i]是我们可以在当前迭代中作为一个整体a的最后一个元素。取a[i+1]的分数等于N/M的小数部分
  • 继续下一个数字,从剩余的a[i+1]部分开始
  • 完成后,数组b将包含总计为 SUM(a)M 个数字。再次遍历阵列,并将结果缩放N/M

以下是它与您的示例的工作方式:

b[0] = a[0] + (2/3)*a[1]              = 2.33333
b[1] = (1/3)*a[1] + a[2] + (1/3)*a[3] = 5
b[2] = (2/3)*a[3] + a[4]              = 7.66666
b[3] = a[5] + (2/3)*a[6]              = 10.6666
b[4] = (1/3)*a[6] + a[7] + (1/3)*a[8] = 13.3333
b[5] = (2/3)*a[8] + a[9]              = 16
                                        --------
                                Total = 55

6/10缩小会产生最终结果:

1.4 3 4.6 6.4 8 9.6 (Total = 33)

下面是C++中的简单实现:

double need = ((double)a.size()) / b.size();
double have = 0;
size_t pos = 0;
for (size_t i = 0 ; i != a.size() ; i++) {
    if (need >= have+1) {
        b[pos] += a[i];
        have++;
    } else {
        double frac = (need-have); // frac is less than 1 because of the "if" condition
        b[pos++] += frac * a[i];   // frac of a[i] goes to current element of b
        have = 1 - frac;
        b[pos] += have * a[i];     // (1-frac) of a[i] goes to the next position of b
    }
}
for (size_t i = 0 ; i != b.size() ; i++) {
    b[i] /= need;
}

演示。

您将需要采用某种形式的插值,因为要平均的元素数不是整数。

您可以考虑计算数组的前缀和,即

0 1 2 3 4 5 6 7 8 9
1 2 3 4 5 6 7 8 9 10

求和产量

0  1  2  3  4  5  6  7  8  9
1  3  6 10 15 21 28 36 45 55

然后执行线性插值以获得缺少的中间值,例如在 0*, 10/6, 20/6, 30/5*, 40/6, 50/6, 60/6* 处。(带星号的很容易获得)。

0  1 10/6 2  3 20/6  4  5  6  40/6  7  8  50/6  9
1  3 15/3 6 10 35/3 15 21 28 100/3 36 45 145/3 55

现在,您可以通过成对减去值来获得小数和。第一个平均值是

(15/3-1)/(10/6) = 12/5

我想不出C++库中有什么东西可以制作出这样的东西,一切都完全煮熟并准备就绪。

所以你几乎必须卷起袖子去上班。在这一点上,什么是"有效"的方法的问题归结为最基本的问题。这意味着:

1)计算输出数组应该有多大。根据问题的描述,您甚至在查看输入数组中的值之前就应该能够进行该计算。你知道输入数组的size(),就可以计算目标数组的size()

2) 因此,您预先resize()目标阵列。现在,您不再需要担心在逐步增加动态输出数组大小所浪费的时间,因为您遍历输入数组并进行计算。

3)所以剩下的就是实际工作:遍历输入数组,并计算缩小的值。

auto b=input_array.begin();
auto e=input_array.end();
auto p=output_array.begin();

除了蛮力迭代和计算之外,这里看不到很多其他选项。从b迭代到e,获取样本,计算每个缩小的值,并将结果值保存到*p++中。