组合对应于向量中重复的相邻值的值

时间:2016-07-28 15:10:29

标签: arrays matlab vector indexing

我需要看起来像这样的数据向量:

A = [1 2 3 3 4 5 6 6 5 4 4 3 3 3 3];
B = [1 5 9 6 4 6 8 2 1 5 7 8 3 2 6];

我想删除A中所有重复的相邻值,并将B中的相应值相加,结果为

A = [1 2 3  4 5 6  5 4  3];
B = [1 5 15 4 6 10 1 12 19];

我可以使用this answer中描述的unique,但这会将所有重复值,重复值组合在一起,而不管顺序如何。我也可以使用diff,如this question中所述,但我不知道如何记录将要合并的索引。

我总是可以遍历矢量,但这似乎是不必要的乏味,我觉得应该有一个更优雅的解决方案。有没有办法在几行内实现这一目标?

1 个答案:

答案 0 :(得分:7)

您可以使用diff来查找不唯一的相邻位置,然后将其与cumsum结合使用,以便您可以生成彼此应属于的不同组。在差异结果中查找非零的任何值将找到那些非唯一但连续的值。将cumsum应用于此结果时,您将生成一个ID数组,该数组从1到多个组不等,其中属于同一ID的所有值都属于同一个连续组。这应该是accumarray的理想输入,我们可以将所有属于每个组的值相加:

Aval = A(:); % Unroll into a column to ensure shape compliance
ind = diff([Inf; Aval]) ~= 0; % Find all unique locations
IDs = cumsum(ind); % Create ID array
Aout = Aval(ind).'; % Determine all unique values per group
Bout = accumarray(IDs(:), B(:)).'; % Find their sum

我承认这不是几行,因为大多数是设置,但核心答案可以在第二行,第三行和最后一行代码中看到。注意accumarray的微妙之处,其中输入必须是列向量。为了强制输入以使它们成为列向量,我使用(:)将向量展开到列中而不管它们的形状如何,尤其是第一行代码。然后我将结果转置到最后,因为accumarray将在这种情况下输出列向量,并且转置将创建行向量,因为您希望行向量作为所需结果。

对于您的测试输入:

A = [1 2 3 3 4 5 6 6 5 4 4 3 3 3 3];
B = [1 5 9 6 4 6 8 2 1 5 7 8 3 2 6];

diff结果的输出结果为:

>> ind.'

ind =

     1     1     1     0     1     1     1     0     1     1     0     1     0     0     0

您可以准确地看到零值对应于非唯一连续位置。运行cumsum后,ID数组的输出结果为:

>> IDs.'

IDs =

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

对ID数组执行cumsum会转换此diff数组,以便每个连续的组都为您提供唯一ID。我们还可以使用ind索引到A以查找每个组的唯一值,即第三行。最后一行对每个组进行求和。请注意,当我展开数据时,第三行被转换为行向量,因此它是一个以列开头的向量。

我们得到了所需的输出:

>> Aout

Aout =

     1     2     3     4     5     6     5     4     3

>> Bout

Bout =

     1     5    15     4     6    10     1    12    19