2013-01-15 18 views
15

Ho due vettori, idx1 e idx2 e voglio ottenere i valori tra di loro. Se idx1 e idx2 erano numeri e non i vettori, avrei potuto farlo nel modo seguente:Vettorizzazione della nozione di due punti (:) - valori tra due vettori in MATLAB

idx1=1; 
idx2=5; 
values=idx1:idx2 

% Result 
% values = 
% 
% 1  2  3  4  5 

Ma nel mio caso, idx1 e idx2 sono vettori di lunghezza variabile. Ad esempio, per lunghezza = 2:

idx1=[5,9]; 
idx2=[9 11]; 

Posso utilizzare l'operatore di due punti per ottenere direttamente i valori in mezzo? Questo è qualcosa di simile al seguente:

values = [5  6  7  8  9  9 10 11] 

so che posso fare idx1(1):idx2(1) e idx1(2):idx2(2), questo è, estrarre i valori per ogni colonna separatamente, in modo se non c'è altra soluzione, posso fare questo con un for-loop, ma forse Matlab può farlo più facilmente.

+0

'values' non è possibile in MATLAB. Un 5-vettore verticalmente concatenato da un 3-vettore? – petrichor

+0

Sì, hai ragione, mi dispiace. Ho intenzione di correggerlo. Non mi importa se i valori sono tutti nella stessa riga, ho solo bisogno di tutti i valori tra questi indici. – Digna

+0

C'è un post di blog eccellente su questo argomento di Loren a Mathworks: [Vettorializzare la nozione di due punti (:)] (http://blogs.mathworks.com/loren/2008/10/13/vectorizing-the-notion- of-colon) – knedlsepp

risposta

11

L'output del campione non è legale. Una matrice non può avere righe di lunghezza diversa. Che cosa si può fare è creare un array di celle utilizzando arrayfun:

values = arrayfun(@colon, idx1, idx2, 'Uniform', false) 

Per convertire la matrice cellulare risultante in un vettore, è possibile utilizzare cell2mat:

values = cell2mat(values); 

In alternativa, se tutti i vettori nella cellula risultante matrice hanno la stessa lunghezza, è possibile costruire una matrice di uscita come segue:

values = vertcat(values{:}); 
+1

Grazie, questo aiuta. Poiché ho solo bisogno dei valori e non mi importa da quale riga li ho ottenuti, posso usare 'horzcat' e' unique', come questo: 'values ​​= unique (horzcat (values ​​{:}));' I Ho intenzione di leggere di più su arrayfun, sembra essere molto utile – Digna

+2

@Digna Può sembrare carino, ma non abusarne. È piuttosto lento se confrontato con un ciclo 'for' (ancor più se esiste una soluzione" vettorizzata "), quindi di solito preferisci quest'ultimo (a meno che la velocità non sia un problema) ... Nota anche che puoi scrivere' [blah blah] 'invece di' horzcat (blah blah) '. –

0

provare a prendere l'unione degli insiemi. Dati i valori di idx1 e idx2 che hai fornito, esegue

values = union(idx1(1):idx1(2), idx2(1):idx2(2)); 

che produrrà un vettore con i valori [5 6 7 8 9 10 11], se lo desideri.

+0

Grazie per aver risposto. Il problema è che 'idx1' e' idx2' possono avere una lunghezza qualsiasi (dipende dal segnale che sto elaborando), e questa soluzione sarebbe difficile da applicare in questo caso, no? (Forse mi manca qualcosa) :) – Digna

+0

Ah, whoops. Scusa, ho frainteso la domanda. Prendere il prodotto cartesiano usando 'arrayfun' sembra essere il modo per andare qui. – benjwadams

0

Non riesco a far funzionare la soluzione di Eitan, a quanto pare è necessario specificare i parametri su due punti. La piccola modifica che segue ottenuto che funziona sulla mia versione R2010b:

step = 1; 
idx1 = [5, 9]; 
idx2 = [9, 11]; 
values = arrayfun(@(x,y)colon(x, step, y), idx1, idx2, 'UniformOutput', false); 
values=vertcat(cell2mat(values)); 

noti che step = 1 è in realtà il valore di default in colon, e Uniform possono essere utilizzati al posto di UniformOutput, ma ho incluso questi per amore di completezza.

0

C'è un ottimo post sul blog di Loren chiamato Vectorizing the Notion of Colon (:). Esso comprende una risposta che è circa 5 volte più veloce (per grandi array) rispetto all'utilizzo arrayfun o un -loop for ed è simile a run-length-decodifica:

L'idea è di ampliare il colon sequenze fuori. Conosco le lunghezze di ciascuna sequenza, quindi conosco i punti di partenza nell'array di output. Riempire i valori dopo i valori iniziali con 1s. Quindi capisco quanto salti dalla fine di una sequenza all'inizio di quella successiva. Se ci sono valori iniziali ripetuti, i salti potrebbero essere negativi.Una volta che questo array è riempito, l'output è semplicemente la somma cumulativa o cumsum della sequenza.

function x = coloncatrld(start, stop) 
% COLONCAT Concatenate colon expressions 
% X = COLONCAT(START,STOP) returns a vector containing the values 
% [START(1):STOP(1) START(2):STOP(2) START(END):STOP(END)]. 

% Based on Peter Acklam's code for run length decoding. 
len = stop - start + 1; 

% keep only sequences whose length is positive 
pos = len > 0; 
start = start(pos); 
stop = stop(pos); 
len = len(pos); 
if isempty(len) 
    x = []; 
    return; 
end 

% expand out the colon expressions 
endlocs = cumsum(len); 
incr = ones(1, endlocs(end)); 
jumps = start(2:end) - stop(1:end-1); 
incr(endlocs(1:end-1)+1) = jumps; 
incr(1) = start(1); 
x = cumsum(incr);