8

Meine Frage ähnelt dieser one, aber ich möchte jedes Element nach einer Anzahl replizieren, die in einem zweiten Array der gleichen Größe angegeben ist.Elementweise Array-Replikation nach einer Zählung

Ein Beispiel dafür, sage ich ein Array hatte v = [3 1 9 4], ich will rep = [2 3 1 5] verwenden, um das erste Element 2 mal zu replizieren, die zweiten drei Mal, und so weiter [3 3 1 1 1 9 4 4 4 4 4] zu bekommen.

Bis jetzt verwende ich eine einfache Schleife, um den Job zu erledigen. Dies ist, was ich begann mit:

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

ich von preallocating Raum verbessern verwaltet:

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 

Allerdings habe ich immer noch das Gefühl, ein cleverer Weg sein muss, dies zu tun ... Danke

+5

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

+1

@Doresoom: Ich dachte, ich, bevor Sie eine Frage wie diese beantwortet hatte, konnte es aber nicht finden. Ich habe es zur gleichen Zeit wie du gejagt.Der Titel und die Tags waren ziemlich unterschiedlich, was es etwas schwierig machte, sie zu finden. – gnovice

Antwort

15

Hier ist ein Weg, Ich mag, dies zu erreichen:

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

Dies funktioniert, indem zuerst einen Index Vektor ze roes die gleiche Länge wie die endgültige Zählung aller Werte. Durch Ausführen einer kumulativen Summe des Vektors rep mit dem letzten entfernten Element und einer 1 am Anfang platzierten, erhalte ich einen Vektor von Indizes in index, der zeigt, wo die Gruppen von replizierten Werten beginnen. Diese Punkte sind mit Einsen markiert. Wenn eine kumulative Summe unter index ausgeführt wird, erhalte ich einen endgültigen Indexvektor, den ich verwenden kann, um in v zu indizieren, um den Vektor von heterogen replizierten Werten zu erzeugen.

+0

könnten Sie einige Kommentare hinzufügen, wie das funktioniert? –

+0

@Nathan: Schon vor dir. =) – gnovice

+1

definitiv eine clevere Art der Verwendung von 'Cumsum' .. Danke! – merv

2

in die Liste der möglichen Lösungen hinzuzufügen, betrachten diese:

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

Das ist viel langsamer als die von gnovice ..

+2

Sie könnten tatsächlich ARRAYFUN verwenden und die Aufrufe von NUM2CELL vermeiden, aber es wäre immer noch * viel * langsamer: http://stackoverflow.com/questions/1975772/matlab-array-manipulation/1975835#1975835. – gnovice

0

Was Sie versuchen zu Run- zu tun ist, Länge decodieren. Ein hoher zuverlässiger/vektorisiert Dienstprogramm ist der FEX submission rude():

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

das Ergebnis

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

Hinweis, dass diese Funktion als auch die entgegengesetzte Operation durchführt, das heißt Lauflängen- kodiert ein Vektor oder in anderen Wörter gibt values und die entsprechende counts zurück.

0

accumarray kann Funktion verwendet werden, um die Code-Arbeit zu machen, wenn Nullen Ausgang in rep Array

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

Diese zur Lösung von gnovice ähnlich funktioniert, mit der Ausnahme, dass anstelle Indizes akkumulierte 1. zugeordnet ist Dies ermöglicht überspringen einige Indizes (3 und 6 im Beispiel unten) und entfernen entsprechende Elemente aus der Ausgabe.

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