我需要看起来像这样的数据向量:
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 :(得分: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