Подсчитайте длины последовательностей последовательных целых чисел в MATLAB

Я хочу подсчитать все длины последовательностей последовательных целых чисел и вернуть их в виде вектора. Например, рассмотрим вектор: x = [1 2 3 4 6 8 9 10 12 13];

Длина будет:

length([1 2 3 4]) = 4;
length([6]) = 1;
length([8 9 10]) = 3;
length([12 13]) = 2;  

Итак, результат, который я хочу создать:

y = [4 1 3 2] 

Как я могу этого добиться?


person Bowecho    schedule 21.01.2015    source источник
comment
Взгляните сюда: mathworks.com/matlabcentral/answers/   -  person Benoit_11    schedule 21.01.2015
comment
Это не точная копия, но она охватывает ваш вопрос и многое другое: печать последовательных чисел   -  person knedlsepp    schedule 21.01.2015
comment
Вы ищете так называемые пробеги x-(1:length(x)). Таким образом, вы можете использовать этот ответ: кодирование длины запуска   -  person knedlsepp    schedule 21.01.2015
comment
@knedlsepp, запуски в RLE обычно считаются последовательностями идентичных значений. Эти две вещи, конечно, близки, но не тождественны. Просто чтобы быть точным.   -  person A. Donda    schedule 21.01.2015
comment
@A.Donda: Если вы вычтете 1:length(x), числа, которые ранее шли подряд, теперь будут идентичными.   -  person knedlsepp    schedule 21.01.2015
comment
@knedlsepp, конечно, как я уже сказал, близко. :-)   -  person A. Donda    schedule 21.01.2015
comment
@A.Donda: Но длина пробега x-(1:length(x)) не только близка, но и именно то, что нам нужно...   -  person knedlsepp    schedule 21.01.2015
comment
@knedlsepp, правда, можно и так посмотреть.   -  person A. Donda    schedule 21.01.2015


Ответы (4)


Это должно помочь:

y = diff(find(diff([nan ; x(:) ; nan]) ~= 1))

Внутренний diff ищет шаги, которые не +1 (разрывы последовательности), find определяет соответствующие позиции (индексы), внешний diff вычисляет длину последовательности как разницу между позициями разрыва последовательности. nan существуют, чтобы убедиться, что последовательность в начале и последовательность в конце вектора найдены путем создания значений diff, отличных от 1.

person A. Donda    schedule 21.01.2015
comment
y = diff(find([0 diff(x) 0] ~= 1)) чтобы избежать NaNs? - person Divakar; 21.01.2015
comment
@Divakar, хм, конечно, но я хотел избежать предположения, что среди чисел не может быть 0 (или -2, -1, ..., если уж на то пошло). Нансы не представляют проблемы, не так ли? - person A. Donda; 21.01.2015
comment
В качестве альтернативы можно сначала выполнить внутренний diff, а затем добавить 1, как в ответе knedlsepps. Что, однако, я нахожу иначе излишне сложным... - person A. Donda; 21.01.2015
comment
Это работает для маленького вектора x, но у меня есть вектор-столбец 542474 на 1, и я получаю следующую ошибку: «Ошибка при использовании horzcat. Размеры объединяемых матриц не согласованы». - person Bowecho; 21.01.2015
comment
Я думаю, это забавно, что вы находите мой ответ слишком сложным, поскольку в основном это одно и то же: diff, find, diff... :-) - person knedlsepp; 21.01.2015
comment
@ user3611812, я только что внес изменения, теперь он может работать с векторами-столбцами. - person A. Donda; 21.01.2015
comment
@knedlsepp, основная идея та же, что и в ответе Л. Мендо, на который вы ссылаетесь. Но нет необходимости в 1:numel(x) и в двух анонимных функциях. - person A. Donda; 21.01.2015
comment
Ну, я думаю, этого никогда не будет, но если когда-нибудь NaN окажется в x, но да, этого не будет. Я просто пытаюсь думать, что это должно обрабатывать все виды данных без каких-либо ошибок. - person Divakar; 21.01.2015
comment
@Divakar, даже если в данных есть наны: nan - nan снова равно nan и, следовательно, не совпадает с +1. Каждый nan в данных, в начале, конце или где-то в середине, появляется как последовательность длины 1 в выходных данных. Если это не ожидаемое поведение, я думаю, проблем нет. - person A. Donda; 21.01.2015
comment
@A.Donda: я не вижу вреда в анонимных функциях. Среда выполнения почти такая же, а функциональный стиль программирования делает решение более самодокументируемым. Также вы можете рассматривать это как повторное использование кода, если уже есть какая-то встроенная функция длины прогона. - person knedlsepp; 21.01.2015
comment
Это тоже работает. Я также пробовал это раньше, но я поставил дополнительную запятую при определении моего вектора-столбца, и я не знал. И тебе спасибо. - person Bowecho; 21.01.2015

Небольшой вариант A. Ответ Донды:

  1. Используйте diff для обнаружения различий больше 1. Это дает значение 1 в конце каждого запуска.
  2. Накапливать в обратном порядке (с помощью cumsum), чтобы присвоить каждому номерную метку. пробег. Накопление выполняется в обратном порядке, поскольку значения 1 на шаге 1 находятся в конце каждого прогона, а не в начале.
  3. Вычислите длину прогона с помощью histc.

Код:

y = [diff(x)>1 1];               %// step 1
y = cumsum(fliplr(y));           %// step 2
y = fliplr(histc(y, 1:y(end)));  %// step 3
person Luis Mendo    schedule 21.01.2015
comment
Почему необходимо накапливать назад? - person A. Donda; 21.01.2015
comment
@A.Donda Поскольку шаг 1 создает единицы в конце каждого прогона. Я отредактирую, чтобы уточнить - person Luis Mendo; 21.01.2015

Это равно длине пробега x - (1:length(x)). Поэтому вы можете использовать:

runLengths = @(x) diff([0, reshape(find(x(1:end-1)~=x(2:end)),1,[]), numel(x)]);
sequenceCounts = @(x) runLengths(x(:)-(1:numel(x)).');
result = sequenceCounts(x);
person knedlsepp    schedule 21.01.2015

x = [1 2 3 4 6 8 9 10 12 13];

consecs = []; % empty vector to store answers
consec = 1; % initialize
for I=2:length(x)
    if x(I)==x(I-1)+1 % this one is consecutive with previous
        consec = consec+1;
    else % this one starts a new set of consecutives
        consecs(end+1) =  consec;
        consec = 1;
    end
end
consecs(end+1)=consec; % remember to include the last consecutives
display(consecs)

Это проверено и работает.

person mwengler    schedule 21.01.2015