Как удалить нулевые компоненты в векторе в Matlab?

36

У меня есть вектор, например

a = [0 1 0 3]

Я хочу превратить a в b, который равен b = [1 3].

Как это сделать вообще? Итак, у меня есть вектор с некоторыми нулевыми компонентами, и я хочу удалить нули и оставить только ненулевые числа?

Теги:

7 ответов

75
Лучший ответ

Если вы просто хотите удалить нули, оставив ненулевые нули в a, тогда самое лучшее решение -

a(a==0) = [];

Это удаляет нулевые элементы, используя подход логической индексации в MATLAB. Когда индекс к вектору является булевым вектором той же длины, что и вектор, то MATLAB может использовать этот логический результат для его индексации. Таким образом, это эквивалентно

a(find(a==0)) = [];

И когда вы устанавливаете некоторые элементы массива в [] в MATLAB, соглашение должно их удалить.

Если вы хотите поместить нули в новый результат b, оставив неизменным, лучший способ, вероятно,

b = a(a ~= 0);

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

b = a(find(a ~= 0));

но mlint в конечном итоге помещает строку как ту, где чисто логический индекс был более эффективным и, следовательно, более уместным.

Как всегда, будьте осторожны с ТОЧНЫМИ испытаниями для нуля или для любого числа, если бы вы приняли элементы a, которые были в пределах некоторого эпсилонского толерантности к нулю. Проводят ли эти тесты как

b = a(abs(a) >= tol);

Это сохраняет только те элементы из a, которые по крайней мере такие же, как ваш допуск.

  • 1
    или для первого примера достаточно a = a(a~=0) , назначение на месте работает нормально. Хороший момент при тестировании против небольшого числа, а не 0.
  • 0
    @woodchips: только что опубликовал сравнение производительности ниже :)
8

Я только что наткнулся на эту проблему и хотел найти что-то о производительности, но не смог, поэтому сам написал тест script:

% Config:
rows = 1e6;
runs = 50;

% Start:
orig = round(rand(rows, 1));

t1 = 0;
for i = 1:runs
    A = orig;
    tic
    A(A == 0) = [];
    t1 = t1 + toc;
end
t1 = t1 / runs;

t2 = 0;
for i = 1:runs
    A = orig;
    tic
    A = A(A ~= 0);
    t2 = t2 + toc;
end
t2 = t2 / runs;

t1
t2
t1 / t2

Итак, вы видите, что решение с использованием A = A(A ~= 0) является более быстрым из двух:)

4

Я часто делал такие вещи. Поэтому я попытался написать простую функцию, которая легко "освобождает" нежелательные элементы. Это немного изменяет логику Matlab, но выглядит хорошо:

b = snip(a,'0')

вы можете найти файл функции по адресу: http://www.mathworks.co.uk/matlabcentral/fileexchange/41941-snip-m-snip-elements-out-of-vectorsmatrices

Он также работает со всеми другими элементами "x", наном или другими.

  • 7
    Это могучий молот, чтобы уничтожить крошечную муху ...
3
b = a(find(a~=0))
  • 2
    достаточно b = a(find(a)) , по умолчанию это поиск ненулевых значений.
  • 5
    или b = a(a~=0) достаточно, подразумевается логическая индексация.
Показать ещё 1 комментарий
2

Вы можете использовать разреженный (a), который возвратит

(1,2) 1

(1,4) 3

Это позволяет вам сохранять информацию о том, где были использованы ненулевые записи.

2

Данные

a=[0  3   0   0   7   10   3   0   1   0   7   7   1   7   4]

Do

aa=nonzeros(a)'

Результат

aa=[3   7   10   3   1   7   7   1   7   4]
  • 0
    Почему бы не сделать этот пост лучше: добавьте ссылку на документацию и используйте правильное выделение кода
  • 0
    Я думаю, что это отличный ответ! Было бы неплохо получить сравнение с другими предложениями.
2

Почему не просто, a=a(~~a) или a(~a)=[]. Это эквивалентно другим подходам, но, конечно, менее ключевым штрихам.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню