2016-07-28 62 views
3

重复相邻值我必须数据的矢量,看起来像这样的值:合并对应于向量

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中所述,但我不知道如何记录将要组合的索引。

我总是可以遍历矢量,但这似乎是不必要的繁琐,我觉得应该有一个更优雅的解决方案。有几种方法可以实现这一点:

+0

我有没有回答你的问题? – rayryeng

+0

@rayryeng终于开始尝试了,它完全符合我的需求。 'cumsum'和'accumarray'这个技巧非常棒! –

+0

嘿嘿,没问题。 'accumarray'和'cumsum'是我最喜欢的两个功能。我很高兴能和你分享这些信息! – rayryeng

回答

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 

我承认,这不是一个几行的大部分是设置,但核心答案见于第二,第三和最后一行代码。请注意0​​的细微处,其中输入要求为列向量。为了强制输入以使它们成为列向量,我使用(:)将向量展开为列,而不管它们的形状如何,特别是对于第一行代码。然后,我最后转置结果,因为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 

您可以准确地看到,这是零对应于非唯一连续的位置值。的ID阵列的输出一旦运行cumsum给出:

>> IDs.' 

IDs = 

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

的ID阵列上执行cumsum,使得每个连续组给你一个唯一的ID变换此diff阵列。我们还可以使用ind来索引A以找到第三行的每个组的唯一值。最后一行总结每个组。请注意,第三行在展开数据时转换为行向量,以便它是一个以列开头的列向量。

我们得到所需的输出:

>> Aout 

Aout = 

    1  2  3  4  5  6  5  4  3 

>> Bout 

Bout = 

    1  5 15  4  6 10  1 12 19