Si j'ai ce vecteur:
[~,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
Je voudrais obtenir la position de chaque numéro unique en fonction de lui-même.
y = sum(triu(x==x.')) % MATLAB 2016b and above
En ce moment j'utilise:
y = [1 2 3 4 5 1 2 3 1 1 2 1 2 3 4]
C'est compact mais évidemment pas efficace en mémoire.
Pour la pure beauté de la programmation MATLAB, j'éviterais d'utiliser un boucle. Avez-vous une meilleure implémentation simple?
Contexte:
Mon objectif final est de trier le vecteur x
mais avec la contrainte qu'un nombre qui apparaît N fois a la priorité sur un autre numéro apparu plus de N
fois:
x = [1 1 1 1 1 2 2 2 3 4 4 6 6 6 6]
5 Réponses :
En supposant que Et maintenant vous pouvez appliquer votre tri final: x
soit trié, voici une alternative vectorisée utilisant unique
, diff
et cumsum
a>: >> [~, 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
[~, index] = unique(x);
y = ones(size(x));
y(index(2:end)) = y(index(2:end))-diff(index).';
y = cumsum(y);
Si vous avez des entiers positifs, vous pouvez utiliser une matrice creuse:
[x_relative_sort ,~] = find(sort(sparse(x ,1:numel(x),true), 2, 'descend'));
De même, x_relative_sort
peut être directement calculé:
[y ,~] = find(sort(sparse(1:numel(x), x, true), 1, 'descend'));
Juste pour la variété, voici une solution basée sur accumarray code>
. Cela fonctionne pour x
triés et contenant des entiers positifs, comme dans la question:
y = cell2mat(accumarray(x(:), x(:), [], @(t){1:numel(t)}).');
Vous pouvez être plus efficace en mémoire en comparant uniquement à unique (x)
, vous n'avez donc pas une grande matrice N * N
mais plutôt N * M
, où N = numel (x), M = numel (unique (x))
.
J'ai utilisé une syntaxe de fonction anonyme pour éviter de déclarer une variable de matrice intermédiaire , nécessaire car il est utilisé deux fois - cela peut probablement être amélioré.
f = @(X) sum(cumsum(X,2).*X); y = f(unique(x).'==x);
Voici ma solution qui ne nécessite pas de tri:
% 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];
Explication:
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;
x = [1 1 1 1 1 2 2 2 3 4 4 6 6 6 6 1 1 1]
est-il une entrée possible? Les hommes, un nombre peut-il apparaître en deux passages séparés?Cela pourrait être l'entrée brute, mais pour faciliter les choses, j'ai déjà trié le tableau. Bien sûr, si vous pouvez trouver une solution qui fonctionne dans les deux cas sans utiliser la fonction de tri, c'est encore mieux!
C'est drôle que cela ait été demandé sur PPCG . Peut-être que certaines des solutions vous donneront des idées