8

Moje pytanie jest podobne do tego one, ale chciałbym replikować każdy element zgodnie z liczbą określoną w drugiej tablicy o tym samym rozmiarze.Replikacja tablic zgodna z elementami według liczby

Przykładem tego, powiedzmy miałem tablicę v = [3 1 9 4], chcę użyć rep = [2 3 1 5] replikować pierwszy element 2 razy, drugi trzy razy, i tak dalej, aby uzyskać [3 3 1 1 1 9 4 4 4 4 4].

Do tej pory używam prostej pętli, aby wykonać zadanie. To, co zaczęło się:

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

udało mi się poprawić przez preallocating przestrzeni:

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 

Jednak nadal czuję tam musi być bardziej sprytny sposób to zrobić ... Dzięki

+5

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

+1

@Doresoom: Myślałem, że odpowiedzi na pytanie, jak to już wcześniej, ale nie mógł go znaleźć. W końcu polowałem na to w tym samym czasie co ty.Tytuł i tagi były zupełnie inne, co sprawiło, że było trochę trudniej je znaleźć. – gnovice

Odpowiedz

15

Oto jeden ze sposobów Lubię to osiągnąć:

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

działa to przez pierwsze stworzenie wektor indeksu ZE roes o tej samej długości, co ostateczna liczba wszystkich wartości. Wykonując skumulowaną sumę wektora rep z ostatnim elementem usuniętym i 1 umieszczonym na początku, otrzymuję wektor indeksów do index pokazujący miejsce rozpoczęcia grup replikowanych wartości. Punkty te są oznaczone tymi znakami. Kiedy suma jest wykonywana na index, otrzymuję końcowy wektor indeksu, którego mogę użyć do zindeksowania w v, aby utworzyć wektor heterogenicznie replikowanych wartości.

+0

Czy możesz dodać komentarze, jak to działa? –

+0

@Nathan: Już przed tobą. =) – gnovice

+1

zdecydowanie sprytny sposób używania 'cumsum' .. Dzięki! – merv

2

Aby dodać do listy możliwych rozwiązań, należy rozważyć ten:

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

Jest to o wiele wolniej niż jeden przez gnovice ..

+2

Możesz rzeczywiście używać ARRAYFUN i unikać połączeń z NUM2CELL, ale nadal będzie to * dużo * wolniej: http://stackoverflow.com/questions/1975772/matlab-array-manipulation/1975835#1975835. – gnovice

0

Co ty próbujesz zrobić to okresiach dekodowanie długości. Wysoki poziom niezawodny/wektorowy narzędzie jest FEX submission rude():

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

wynikiem

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

Funkcja ta realizuje operację odwrotną, jak również, np prowadzony długości koduje wektorem lub w innych słowa zwracają values i odpowiadające im counts.

0

accumarray funkcja może być wykorzystywana do prac kodu Zera wyjście w rep tablicy

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

ta działa podobnie do roztworu gnovice, z wyjątkiem, że wskaźniki są gromadzone, a nie jest przypisany do 1. Pozwala to pominąć niektóre indeksy (3 i 6 w poniższym przykładzie) i usuń odpowiednie elementy z wyjścia.

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