Удаление всех нулевых значений, кроме тех, которые фланкируют ненулевые значения

Учитывая вектор:

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);

Это работает следующим образом:

  1. Перерабатывать a к вектору нулей или единиц (abs(sign(a))), с нулем, если запись a ноль и один в противном случае.
  2. Свернуть с маской из трех (conv(..., ones(3,1), 'same')). Таким образом, ненулевое значение в a производит ненулевой результат в своей позиции и в соседних позициях.
  3. Это сравнивается с нулем, чтобы создать логический вектор, с которым 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)] );

Вы можете думать об этом как о поиске "какие значения оставить", а не "какие значения удалить", где самый простой способ определить, какие значения сохранить, это "все ненулевые элементы и нулевые элементы, которые имеют ненулевые значения либо боковая сторона".

Другие вопросы по тегам