计算数组中的重复整数
Count repeating integers in an array
如果我有这个向量:
x = [1 1 1 1 1 2 2 2 3 4 4 6 6 6 6]
我想根据自己得到每个唯一数字的位置。
y = [1 2 3 4 5 1 2 3 1 1 2 1 2 3 4]
目前我正在使用:
y = sum(triu(x==x.')) % MATLAB 2016b and above
它很紧凑,但显然内存效率不高。
为了 MATLAB 编程的纯粹美感,我会避免使用循环。你有更好的简单实现吗?
上下文:
我的最终目标是对向量 x
进行排序,但限制条件是出现 N
次的数字优先于另一个出现超过 N
次的数字:
[~,ind] = sort(y);
x_relative_sort = x(ind);
% x_relative_sort = 1 2 3 4 6 1 2 4 6 1 2 6 1 6 1
假设 x
已排序,这是一个使用 unique
, diff
, and cumsum
的矢量化替代方案:
[~, index] = unique(x);
y = ones(size(x));
y(index(2:end)) = y(index(2:end))-diff(index).';
y = cumsum(y);
现在您可以应用最终排序:
>> [~, ind] = sort(y);
>> x_relative_sort = x(ind)
x_relative_sort =
1 2 3 4 6 1 2 4 6 1 2 6 1 6 1
如果你有正整数,你可以使用稀疏矩阵:
[y ,~] = find(sort(sparse(1:numel(x), x, true), 1, 'descend'));
同样x_relative_sort
可以直接计算:
[x_relative_sort ,~] = find(sort(sparse(x ,1:numel(x),true), 2, 'descend'));
为了多样化,这里有一个基于 accumarray
的解决方案。它适用于 x
排序并包含正整数,如问题:
y = cell2mat(accumarray(x(:), x(:), [], @(t){1:numel(t)}).');
仅与 unique(x)
相比,您可以提高内存效率,因此您没有大的 N*N
矩阵,而是 N*M
,其中 N=numel(x), M=numel(unique(x))
。
我使用了匿名函数语法来避免声明中间矩阵变量,因为它被使用了两次所以需要它 - 这可能会得到改进。
f = @(X) sum(cumsum(X,2).*X); y = f(unique(x).'==x);
这是我的不需要排序的解决方案:
x = [1 1 1 1 1 2 2 2 3 4 4 6 6 6 6 1 1 1];
y = cell2mat( splitapply(@(v){cumsum(v)},x,cumsum(logical([1 diff(x)]))) ) ./ x;
解释:
% Turn each group new into a unique number:
t1 = cumsum(logical([1 diff(x)]));
% x = [1 1 1 1 1 2 2 2 3 4 4 6 6 6 6 1 1 1];
% t1 = [1 1 1 1 1 2 2 2 3 4 4 5 5 5 5 6 6 6];
% Apply cumsum separately to each group:
t2 = cell2mat( splitapply(@(v){cumsum(v)},x,t1) );
% t1 = [1 1 1 1 1 2 2 2 3 4 4 5 5 5 5 6 6 6];
% t2 = [1 2 3 4 5 2 4 6 3 4 8 6 12 18 24 1 2 3];
% Finally, divide by x to get the increasing values:
y = t2 ./ x;
% x = [1 1 1 1 1 2 2 2 3 4 4 6 6 6 6 1 1 1];
% t2 = [1 2 3 4 5 2 4 6 3 4 8 6 12 18 24 1 2 3];
如果我有这个向量:
x = [1 1 1 1 1 2 2 2 3 4 4 6 6 6 6]
我想根据自己得到每个唯一数字的位置。
y = [1 2 3 4 5 1 2 3 1 1 2 1 2 3 4]
目前我正在使用:
y = sum(triu(x==x.')) % MATLAB 2016b and above
它很紧凑,但显然内存效率不高。
为了 MATLAB 编程的纯粹美感,我会避免使用循环。你有更好的简单实现吗?
上下文:
我的最终目标是对向量 x
进行排序,但限制条件是出现 N
次的数字优先于另一个出现超过 N
次的数字:
[~,ind] = sort(y);
x_relative_sort = x(ind);
% x_relative_sort = 1 2 3 4 6 1 2 4 6 1 2 6 1 6 1
假设 x
已排序,这是一个使用 unique
, diff
, and cumsum
的矢量化替代方案:
[~, index] = unique(x);
y = ones(size(x));
y(index(2:end)) = y(index(2:end))-diff(index).';
y = cumsum(y);
现在您可以应用最终排序:
>> [~, ind] = sort(y);
>> x_relative_sort = x(ind)
x_relative_sort =
1 2 3 4 6 1 2 4 6 1 2 6 1 6 1
如果你有正整数,你可以使用稀疏矩阵:
[y ,~] = find(sort(sparse(1:numel(x), x, true), 1, 'descend'));
同样x_relative_sort
可以直接计算:
[x_relative_sort ,~] = find(sort(sparse(x ,1:numel(x),true), 2, 'descend'));
为了多样化,这里有一个基于 accumarray
的解决方案。它适用于 x
排序并包含正整数,如问题:
y = cell2mat(accumarray(x(:), x(:), [], @(t){1:numel(t)}).');
仅与 unique(x)
相比,您可以提高内存效率,因此您没有大的 N*N
矩阵,而是 N*M
,其中 N=numel(x), M=numel(unique(x))
。
我使用了匿名函数语法来避免声明中间矩阵变量,因为它被使用了两次所以需要它 - 这可能会得到改进。
f = @(X) sum(cumsum(X,2).*X); y = f(unique(x).'==x);
这是我的不需要排序的解决方案:
x = [1 1 1 1 1 2 2 2 3 4 4 6 6 6 6 1 1 1];
y = cell2mat( splitapply(@(v){cumsum(v)},x,cumsum(logical([1 diff(x)]))) ) ./ x;
解释:
% Turn each group new into a unique number:
t1 = cumsum(logical([1 diff(x)]));
% x = [1 1 1 1 1 2 2 2 3 4 4 6 6 6 6 1 1 1];
% t1 = [1 1 1 1 1 2 2 2 3 4 4 5 5 5 5 6 6 6];
% Apply cumsum separately to each group:
t2 = cell2mat( splitapply(@(v){cumsum(v)},x,t1) );
% t1 = [1 1 1 1 1 2 2 2 3 4 4 5 5 5 5 6 6 6];
% t2 = [1 2 3 4 5 2 4 6 3 4 8 6 12 18 24 1 2 3];
% Finally, divide by x to get the increasing values:
y = t2 ./ x;
% x = [1 1 1 1 1 2 2 2 3 4 4 6 6 6 6 1 1 1];
% t2 = [1 2 3 4 5 2 4 6 3 4 8 6 12 18 24 1 2 3];