Подсчет повторяющихся целых чисел в массиве - PullRequest
0 голосов
/ 07 января 2019

Если у меня есть этот вектор:

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

Ответы [ 5 ]

0 голосов
/ 08 января 2019

Вот мое решение, которое не требует сортировки:

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];
0 голосов
/ 08 января 2019

Вы можете более эффективно использовать память, сравнивая только с 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);
0 голосов
/ 07 января 2019

Если у вас есть положительные целые числа, вы можете использовать разреженную матрицу:

[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'));
0 голосов
/ 08 января 2019

Только для разнообразия, вот решение, основанное на accumarray. Это работает для x отсортированных и содержащих положительные целые числа, как в вопросе:

y = cell2mat(accumarray(x(:), x(:), [], @(t){1:numel(t)}).');
0 голосов
/ 07 января 2019

Предполагается, что x отсортировано, вот одна векторизованная альтернатива, использующая unique, diff и 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
...