Вот решение, которое
- Адекватно обрабатывает числа, которые не образуют диапазон . Например,
[1 3 5 9]
будет выводиться как '[1:2:5 9]'
. Точно так же [1 3 5 9 11]
даст '[1:2:5 9 11]'
. - Пропуски, указывающие step
1
. Например, [9 3 4 5]
даст [9 3:5]
. - Пропускает ненужные скобки . Например,
[8 6 4 2]
даст '8:-2:2'
, а 5
даст '5'
. - Позволяет пустой ввод . Так что
[]
даст '[]'
.
x = [2 4.5 7 9.5 9 8 7 6 5 15 7.5 7 6.5 6 9 11]; % example input
sep = ' '; % define separator; it could also be comma
str = ''; % initiallize output
k = 1; % first number not processed yet
while k<=numel(x)
m = find(diff([diff(x(k:end)) inf]), 1) + 1; % may be empty
if m>2 % if non-empty and at least 2: range found (at least 3 numbers)
ini = x(k);
ste = x(k+1)-x(k);
fin = x(k+m-1);
if ste~=1
str = [str num2str(ini) ':' num2str(ste) ':' num2str(fin)];
else
str = [str num2str(ini) ':' num2str(fin)];
end
k = k+m; % m numbers have been processed
else % no range: include just one number
str = [str num2str(x(k))];
k = k+1; % 1 number has been processed
end
str = [str sep]; % add separator
end
str = strip(str,sep); % this removes trailing space/comma, if it exists. For pre-2016b, use `strtrim`
if any(str==sep) || isempty(str)
str = ['[' str ']']; % brackets are required
end
Примеры / тесты:
[2 4.5 7 9.5 9 8 7 6 5 15 7.5 7 6.5 6 9 11]
дает '[2:2.5:9.5 9:-1:5 15 7.5:-0.5:6 9 11]'
[1.5 16 -0.5 -7 -9 -11]
т '[1.5 16 -0.5 -7:-2:-11]'
[4 2 0 -2 5 12 19]
т '[4:-2:-2 5:7:19]'
[-2 0 2.5 5.5]
т '[-2 0 2.5 5.5]'
[2 3 4 10 7 8]
т'[2:4 10 7 8]'
[6 4.5 3]
т '6:-1.5:3'
[3 4 5 6]
т '3:6'
42
т '42'
[]
дает '[]'
Код состоит из цикла, который ищет диапазон максимальной длины, начиная с текущей позиции, а затем двигается вперед. самая хитрая часть - это строка
m = find(diff([diff(x(k:end)) inf]), 1) + 1; % may be empty
Это пытается найти максимальную длину m
чисел, образующих диапазон,начиная с текущей позиции k
. diff(x(k:end))
вычисляет последовательные различия, а внешний diff
обнаруживает изменения в этих различиях. Первое такое изменение, вычисленное с find(..., 1)
, указывает на первое число, которое не принадлежит диапазону. Существует пять случаев, второй из которых объясняет, почему необходим inf
:
- Правильный диапазон из 3 или более чисел, за которым следует хотя бы число, не входящее в этот диапазон . Например, если
x(k:end)
равно [3 5 7 15]
, то diff(x(k:end))
равно [2 2 8]
, diff([diff(x(k:end)) inf])
равно [0 6 inf]
, find(..., 1)
дает 2
, а m
равно 3
. - Правильный диапазон из 3 или более чисел, который заканчивается массивом . Например, если
x(k:end)
равно [3 5 7]
, то diff(x(k:end))
равно [2 2]
, diff([diff(x(k:end)) inf])
равно [0 inf]
, find(..., 1)
дает 2
, а m
равно 3
. Вот почему inf
необходим;без него результатом будет m=[]
, что будет неправильно интерпретировано как "отсутствие диапазона" ветвью if
. - Нет правильного диапазона;осталось более 2 номеров . Например, если
x(k:end)
равно [3 6 7]
, то diff(x(k:end))
равно [3 1]
, diff([diff(x(k:end)) inf])
равно [-2 inf]
, find(..., 1)
дает 1
, а m
равно 2
. Это означает, что - это диапазон двух чисел;но это не правильный диапазон, поэтому ветвь if
будет игнорировать его, и выполнение продолжится с частью else
. - Нет правильного диапазона;осталось только 2 номера . Например, если
x(k:end)
равно [3 6]
, то diff(x(k:end))
равно 3
, diff([diff(x(k:end)) inf])
равно [inf]
, find(..., 1)
дает 1
, а m
равно 2
. Опять же, есть диапазон из двух чисел, но это не правильный диапазон. Обратите внимание, что без включенного inf
у нас было бы m=[]
вместо «правильного» * 1161 *, но это также было бы допустимо для запуска части else
(в которой фактическое значение m
не используется). - Нет правильного диапазона;осталось только 1 число, то есть текущее число оканчивает массив . Например,
if x(k:end)
это просто 3
, у нас diff(x(k:end))
равно []
, diff([diff(x(k:end)) inf])
равно []
, find(..., 1)
дает []
, а m
равно []
. Хотя m
"должно" быть 1
, []
так же верно для запуска части else
.
Обратите внимание, что, поскольку вход содержит целые числа или половину целых, есть нет проблем с плавающей точкой , так как эти числа представлены с точностью до ± 2^52
.