Векторизация понятия двоеточия (:) - значения между двумя векторами в MATLAB

У меня есть два вектора, idx1 и idx2, и я хочу получить значения между ними. Если бы idx1 и idx2 были числами, а не векторами, я мог бы сделать это следующим образом:

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

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

Но в моем случае idx1 и idx2 - векторы переменной длины. Например, для length = 2:

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

Могу ли я использовать оператор двоеточия для прямого получения значений между ними? Это что-то похожее на следующее:

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

Я знаю, что могу делать idx1(1):idx2(1) и idx1(2):idx2(2), то есть извлекать значения для каждого столбца отдельно, поэтому, если нет другого решения, я могу сделать это с помощью цикла for, но, возможно, Matlab может сделать это проще.


person Digna    schedule 15.01.2013    source источник
comment
values невозможно в MATLAB. 5-вектор, вертикально связанный с 3-вектором?   -  person petrichor    schedule 15.01.2013
comment
Да, извините, вы правы. Я исправлю это. Я не возражаю, если все значения находятся в одной строке, мне просто нужны все значения между этими индексами.   -  person Digna    schedule 15.01.2013
comment
На эту тему есть отличное сообщение в блоге Лорен в Mathworks: Векторизация понятия толстой кишки (:)   -  person knedlsepp    schedule 11.03.2015


Ответы (4)


Ваш образец вывода недопустим. В матрице не может быть строк разной длины. Что вы можете сделать, так это создать массив ячеек, используя arrayfun:

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

Чтобы преобразовать полученный массив ячеек в вектор, вы можете использовать cell2mat:

values = cell2mat(values);

В качестве альтернативы, если все векторы в результирующем массиве ячеек имеют одинаковую длину, вы можете построить выходную матрицу следующим образом:

values = vertcat(values{:});
person Eitan T    schedule 15.01.2013
comment
Спасибо, это помогает. Поскольку мне просто нужны значения, и я не против, из какой строки я их получил, я могу использовать horzcat и unique, например: values = unique(horzcat(values{:})); Я собираюсь прочитать больше о arrayfun, это кажется очень полезным - person Digna; 15.01.2013
comment
@Digna Это может выглядеть красиво, но не злоупотребляйте этим. Это довольно медленно по сравнению с циклом for (тем более, если существует векторизованное решение), поэтому вы обычно должны предпочесть последнее (если только скорость не является проблемой) ... Также обратите внимание, что вы можете написать [blah blah] вместо horzcat(blah blah). - person Eitan T; 15.01.2013

Попробуйте взять объединение наборов. Учитывая указанные вами значения idx1 и idx2, запустите

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

Что даст вектор со значениями [5 6 7 8 9 10 11], если необходимо.

person benjwadams    schedule 15.01.2013
comment
Спасибо за ответ. Проблема в том, что idx1 и idx2 могут иметь любую длину (это зависит от сигнала, который я обрабатываю), и это решение было бы трудно применить в этом случае, не так ли? (Возможно, мне что-то не хватает) :) - person Digna; 15.01.2013
comment
Ах, упс. Извините, я неправильно понял вопрос. Здесь можно использовать декартово произведение с использованием arrayfun. - person benjwadams; 15.01.2013

Мне не удалось заставить решение @Eitan работать, по-видимому, вам нужно указать параметры для двоеточия. Следующая небольшая модификация заставила его работать на моей версии 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));

Обратите внимание, что step = 1 фактически является значением по умолчанию в colon, а Uniform можно использовать вместо UniformOutput, но я включил их для полноты картины.

person Lord Henry Wotton    schedule 27.05.2013

В блоге Лорен есть отличный пост под названием Векторизация понятия двоеточия (:). Он включает ответ, который примерно в 5 раз быстрее (для больших массивов), чем при использовании arrayfun или for-цикла, и аналогичен декодированию длины прогона:

Идея состоит в том, чтобы расширить последовательности двоеточия. Я знаю длину каждой последовательности, поэтому я знаю начальные точки в выходном массиве. Заполните значения после начальных значений единицами. Затем я прикидываю, на сколько прыгнуть от конца одной последовательности к началу следующей. Если есть повторяющиеся начальные значения, скачки могут быть отрицательными. Как только этот массив заполнен, на выходе получается просто совокупная сумма или совокупная сумма последовательности.

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);
person Community    schedule 10.03.2015