我有一组值,其中一些有重复,例如:
a = [5;5;4;7;7;3;3;9;5;7]
我希望找到哪些是重复的,然后按顺序对每个进行编号,同时使非重复为零。例如:
b = [1;1;0;2;2;3;3;0;1;2]
目前,我使用unique
函数和各种for
循环和if
语句,效率非常低且不完整,但我觉得应该有一个简单的答案。
获得此答案的最有效方法是什么?
答案 0 :(得分:2)
您可以结合使用unique
,accumarray
和ismember
进行必要的调整:
a = [5;5;4;7;7;3;3;9];
% Identify unique values and their counts
[uniquevals, ~, ia] = unique(a, 'stable'); % Stable keeps it in the same order
bincounts = accumarray(ia, 1); % Count the frequency of each index in ia
% Zero out singles
singles = uniquevals(bincounts <= 1);
[~, singleidx] = intersect(a, singles);
a(singleidx) = 0;
% Overwrite repeats
repeats = uniquevals(bincounts > 1);
[~, a] = ismember(a, repeats);
返回新的a
:
a =
1 1 0 2 2 3 3 0
我们在这里使用unique
来查找输入数组a
中的所有唯一值。我们还存储可选的第三个输出,它是a
的值到唯一值数组中的索引的映射。请注意,我们使用stable
选项按照a
中首次遇到的顺序获取唯一值; unique
的结果默认排序。
然后我们使用accumarray
来累积我们从unique
获得的下标,它们给出了每个索引的计数。使用logical indexing,我们首先使用这些计数将单个实例清零。在这些被清零之后,我们可以滥用使用ismember
的第二个输出来返回最终答案。
答案 1 :(得分:2)
以下是基于索引,逻辑运算符和cumsum的解决方案:
x = [false; a(2:end)==a(1:end-1)]; %logical indexes of repeated elements except the first element of each block
y = [x(2:end)|x(1:end-1) ;x(end)]; %logical indexes of repeated elements
result = cumsum(~x&y).*y %cumsum(...):number all elements sequentially and (... .* y): making non-duplicates zero
修改强>
编辑问题时,要操作非连续重复项,您可以执行以下操作:
[s ii] = sort(a);
x = [false ;s(2:end)==s(1:end-1)];
y = [x(2:end)|x(1:end-1) ;x(end)];
first = ~x&y;
[~,ix]=sort(ii(first));
un(ix,1)=1:numel(ix);
result(ii,1)=un(cumsum(first)).*y;
答案 2 :(得分:2)
这是另一种方法:
a = [5;5;4;7;7;3;3;9;5;7];
[u, ~, w] = unique(a, 'stable');
s = find(sum(bsxfun(@eq, a, u.'), 1) > 1);
b = sum(bsxfun(@times, bsxfun(@eq, w, s), 1:numel(s)), 2);
在R2016b之后,您可以简化语法:
a = [5;5;4;7;7;3;3;9;5;7];
[u, ~, w] = unique(a, 'stable');
s = find(sum(a==u.', 1) > 1);
b = sum((w==s).*(1:numel(s)), 2);
答案 3 :(得分:1)
这是一个两个班轮,也适用于非连续重复
[c, ia, ic] = unique(a, 'stable');
[~, b] = ismember(a, a(ia(accumarray(ic,1)>1)));
我使用了来自@excaza answer的一些想法并进行了修改。