8

Ma question est similaire à cette one, mais je voudrais répliquer chaque élément en fonction d'un nombre spécifié dans un second tableau de la même taille.Réplication de tableau par élément en fonction d'un nombre

Un exemple de cela, dire que j'avais un tableau v = [3 1 9 4], je veux utiliser rep = [2 3 1 5] pour reproduire le premier élément 2 fois, trois fois deuxième, et ainsi de suite pour obtenir [3 3 1 1 1 9 4 4 4 4 4]. Jusqu'à présent, j'utilise une simple boucle pour faire le travail. C'est ce que j'ai commencé avec:

vv = []; 
for i=1:numel(v) 
    vv = [vv repmat(v(i),1,rep(i))]; 
end 

J'ai réussi à améliorer l'espace par préallocation:

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 

Cependant, je pense toujours qu'il doit y avoir un moyen de faire plus intelligent cette ... Merci

+5

voir http://stackoverflow.com/questions/1975772/matlab-array-manipulation – Doresoom

+1

@Doresoom: Je pensais avoir répondu à une question comme ça avant, mais n'a pas pu le trouver. Je l'ai finalement traqué en même temps que toi.Le titre et les tags étaient très différents, ce qui était un peu difficile à trouver. – gnovice

Répondre

15

est ici d'une façon que je veux y arriver:

>> 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 

cela fonctionne en créant d'abord un vecteur d'indices de ze roes la même longueur que le compte final de toutes les valeurs. En effectuant une somme cumulative du vecteur rep avec le dernier élément supprimé et un 1 placé au début, j'obtiens un vecteur d'indices en index montrant où commenceront les groupes de valeurs répliquées. Ces points sont marqués d'un. Quand une somme cumulative est effectuée sur index, j'obtiens un vecteur d'index final que je peux utiliser pour indexer en v pour créer le vecteur de valeurs répliquées de façon hétérogène.

+0

pourriez-vous ajouter quelques commentaires de comment cela fonctionne? –

+0

@Nathan: Déjà en avance sur toi. =) – gnovice

+1

certainement une façon intelligente d'utiliser 'cumsum' .. Merci! – merv

2

Pour ajouter à la liste des solutions possibles, considérer celle-ci:

vv = cellfun(@(a,b)repmat(a,1,b), num2cell(v), num2cell(rep), 'UniformOutput',0); 
vv = [vv{:}]; 

Ceci est beaucoup plus lent que celui par gnovice ..

+2

Vous pourriez réellement utiliser ARRAYFUN et éviter les appels à NUM2CELL, mais ce serait toujours * beaucoup * plus lent: http://stackoverflow.com/questions/1975772/matlab-array-manipulation/1975835#1975835. – gnovice

0

Qu'est-ce que vous essayez de faire est de Exécuter- longueur décoder. Un utilitaire fiable/vectorisée haut niveau est le FEX submission rude():

% example inputs 
counts = [2, 3, 1]; 
values = [24,3,30]; 

le résultat

rude(counts, values) 
ans = 
    24 24  3  3  3 30 

Notez que cette fonction effectue l'opération inverse, ainsi, à savoir de longueur de code pour un vecteur ou dans d'autres mots renvoie values et le counts correspondant.

0

accumarray fonction peut être utilisée pour faire fonctionner le code si des zéros sortie dans rep tableau

function vv = repeatElements(v, rep) 
index = accumarray(cumsum(rep)'+1, 1); 
vv = v(cumsum(index(1:end-1))+1); 
end 

Cela fonctionne comme solution de gnovice, sauf que les indices sont accumulés au lieu d'être affectés à 1. Cela permet de sauter certains indices (3 et 6 dans l'exemple ci-dessous) et supprime les éléments correspondants de la sortie.

>> 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