Удаление всех нулевых значений, кроме тех, которые фланкируют ненулевые значения
Учитывая вектор:
a = [0;0;2;3;0;2;10;11;0;0;0;4;5;8;0;0;0]
Кто-нибудь может показать или предложить способ удалить все нулевые значения, кроме тех, которые фланкируют ненулевые значения?
Желаемый результат для вышеупомянутого будет:
b = [0;2;3;0;2;10;11;0;0;4;5;8;0]
Где эти значения были удалены:
[0; 0; 2; 3; 0; 2; 10; 11; 0;0; 0; 4; 5; 8; 0;0;0]
Я не уверен, с чего начать с этой проблемы, не прибегая к использованию набора операторов IF, таких как:
for k=1:length(a)
if a(k) == 0 && a(k+1) == 0
*delete value*
end
if a(k) == 0 && a(k+1) >0
*keep/store value*
end
if a(k) > 0
*keep/store value*
end
if a(k) == 0 && a(k-1) >0
*keep/store value*
end
end
И так далее.
3 ответа
Если вы создаете два дополнительных вектора, один смещается влево, другой вправо от вашего вектора a
(РЕДАКТИРОВАТЬ: используя circshift
как предложено в комментариях ниже):
a = [0;0;2;3;0;2;10;11;0;0;0;4;5;8;0;0;0];
a_right = circshift(a,-1);
a_left = circshift(a,1);
Создайте матрицу М:
M = [a,a_right,a_left];
И суммируем каждую строку:
s = sum(M,2);
Затем найдите компоненты, которые отличаются от 0:
i = find(s~=0);
Это даст вам правильные индексы для выбора из вашего исходного вектора:
b=a(i)
Я получил:
b=[0;2;3;0;2;10;11;0;0;4;5;8;0]
Вы можете использовать свертку:
b = a(conv(abs(sign(a)), ones(3,1), 'same')>0);
Это работает следующим образом:
- Перерабатывать
a
к вектору нулей или единиц (abs(sign(a))
), с нулем, если записьa
ноль и один в противном случае. - Свернуть с маской из трех (
conv(..., ones(3,1), 'same')
). Таким образом, ненулевое значение вa
производит ненулевой результат в своей позиции и в соседних позициях. - Это сравнивается с нулем, чтобы создать логический вектор, с которым
a
индексируется (a(...>0)
).
Это может быть легко обобщено, чтобы держать более отдаленных соседей. В частности, используйте маску ones(2*N+1,1)
сохранить нулевые значения, которые до N
записи от ненулевых значений.
У меня есть другая идея (предоставленная, не сильно отличающаяся от двух других), использующая логическое индексирование:
a(~(~a & ~[diff(a);0] & ~[0;diff(a)] ));
Объяснение:
~
- логическое значениеnot
, возвращает логическое значение, представляющее "противоположность" ввода.~a
- возвращает ноль элементовa
(это не требуется в приведенном вами примере, но важно, если у вас есть повторяющиеся ненулевые значения, которые вы хотели бы сохранить).~[diff(a);0] & ~[0;diff(a)]
- вернуть значения, чья производная по любому размеру равна нулю.a(~(...))
- вернуть значенияa
которые не являются "нулями с одинаковыми значениями с обеих сторон", чтоb
,
Другой способ написать то же самое (используя законы Де Моргана и используя "правдивость" ненулевых значений):
a( a | [diff(a);0] | [0;diff(a)] );
Вы можете думать об этом как о поиске "какие значения оставить", а не "какие значения удалить", где самый простой способ определить, какие значения сохранить, это "все ненулевые элементы и нулевые элементы, которые имеют ненулевые значения либо боковая сторона".