Replica dell'array per elementi in base a un conteggio [duplicato
-
24-09-2019 - |
Domanda
Questa domanda ha già una risposta qui:
La mia domanda è simile a questa uno, ma vorrei replicare ogni elemento in base a un conteggio specificato in un secondo array della stessa dimensione.
Un esempio di questo, dire che avevo un array v = [3 1 9 4]
, Voglio usare rep = [2 3 1 5]
per replicare il primo elemento 2 volte, il secondo tre volte e così via per ottenere [3 3 1 1 1 9 4 4 4 4 4]
.
Finora sto usando un semplice ciclo per fare il lavoro. Questo è ciò con cui ho iniziato:
vv = [];
for i=1:numel(v)
vv = [vv repmat(v(i),1,rep(i))];
end
Sono riuscito a migliorare preallocando lo spazio:
vv = zeros(1,sum(rep));
c = cumsum([1 rep]);
for i=1:numel(v)
vv(c(i):c(i)+rep(i)-1) = repmat(v(i),1,rep(i));
end
Comunque sento ancora che ci deve essere un modo più intelligente per farlo ... grazie
Soluzione
Ecco un modo in cui mi piace realizzare questo:
>> index = zeros(1,sum(rep));
>> index(cumsum([1 rep(1:end-1)])) = 1;
index =
1 0 1 0 0 1 1 0 0 0 0
>> index = cumsum(index)
index =
1 1 2 2 2 3 4 4 4 4 4
>> vv = v(index)
vv =
3 3 1 1 1 9 4 4 4 4 4
Questo funziona prima creando un vettore indice di zero della stessa lunghezza del conteggio finale di tutti i valori. Eseguendo una somma cumulativa del rep
Vector con l'ultimo elemento rimosso e un 1 posizionato all'inizio, ottengo un vettore di indici in index
mostrando dove inizieranno i gruppi di valori replicati. Questi punti sono contrassegnati da quelli. Quando viene eseguita una somma cumulativa index
, Ottengo un vettore indice finale che posso usare per indicizzare v
Per creare il vettore di valori eterogenei.
Altri suggerimenti
Per aggiungere all'elenco di possibili soluzioni, considera questo:
vv = cellfun(@(a,b)repmat(a,1,b), num2cell(v), num2cell(rep), 'UniformOutput',0);
vv = [vv{:}];
Questo è molto più lento di quello di Gnovice..
Quello che stai cercando di fare è decodifica della lunghezza. Un'utilità di alto livello affidabile/vettoriale è la Presentazione FEX rude()
:
% example inputs
counts = [2, 3, 1];
values = [24,3,30];
il risultato
rude(counts, values)
ans =
24 24 3 3 3 30
Si noti che questa funzione esegue anche l'operazione opposta, cioè codifica di lunghezza un vettore o in altre parole ritorna values
e il corrispondente counts
.
accumarray
La funzione può essere utilizzata per far funzionare il codice se gli zeri escono rep
Vettore
function vv = repeatElements(v, rep)
index = accumarray(cumsum(rep)'+1, 1);
vv = v(cumsum(index(1:end-1))+1);
end
Questo funziona simile alla soluzione di Gnovice, tranne per il fatto che gli indici vengono accumulati invece assegnati a 1. Ciò consente di saltare alcuni indici (3 e 6 nell'esempio seguente) e rimuovere gli elementi corrispondenti dall'output.
>> v = [3 1 42 9 4 42];
>> rep = [2 3 0 1 5 0];
>> index = accumarray(cumsum(rep)'+1, 1)'
index =
0 0 1 0 0 2 1 0 0 0 0 2
>> cumsum(index(1:end-1))+1
ans =
1 1 2 2 2 4 5 5 5 5 5
>> vv = v(cumsum(index(1:end-1))+1)
vv =
3 3 1 1 1 9 4 4 4 4 4