2012-06-29 3 views
2

Итак, у меня есть набор из двух списков точек x, y, z.Matlab нативный способ устранения x y баллов

List1 and List2. 

Я хотел бы удалить все точки, которые существуют в List1, которые также существуют в List2. В этом примере большинство точек в List2 (вероятно, 100%) будут существовать в List1. Пример:

List1

1, 2, 3 
4, 5, 6 
7, 8, 9 

List2

7, 8, 9 

Выход

1, 2, 3 
4, 5, 6 

Это будет происходить на тысячах точек на размер списка. Очевидно, это можно сделать, перейдя через List2 и список поиска 1, который имеет время O (n * m). Существует ли более быстрый и малый язык для этого?

Спасибо за помощь.

+0

В зависимости от вашей версии Matlab, посмотрите на функцию '' intersect' (http://www.mathworks.com.au/help/techdoc/ref/intersect.html)? Что-то вроде 'intersect (List1, List2, 'rows')'? (помните о gotchas о предыдущих версиях 'intersect', как описано в статье) –

ответ

4

Try: SETDIFF(List1, List2, 'rows')

(я не знаю, насколько эффективно это, но так как это нативный метод это, вероятно, оптимизирован.)

+0

Вы должны упомянуть, что вы можете использовать параметр setOrder, чтобы указать, должен ли результат сортироваться или быть стабильным, если это имеет значение. – tmpearce

2

@setdiff вариант Turix должен работать. Другой вариант (только для пинков) является

List1(~ismember(List1,List2,'rows'), :); 
2

Я нашел немного быстрее (хотя и менее общий) способ сделать это. Первый ответ так медведь со мной, как я изучаю форматирование ...

я не нашел примечательные эффектов масштабирования, так что я буду использовать в качестве примера следующих списков объектов:

example_step=3; 
max_value_outer=example_step*333; 
max_value_inner=example_step*33; 
List1=[1:example_step:max_value_outer; 2:example_step:max_value_outer; 3:example_step:max_value_outer]'; 
List2=[1:example_step:max_value_inner; 2:example_step:max_value_inner; 3:example_step:max_value_inner]'; 

Turix встроенного setdiff вызова обеспечивает наилучшие результаты до сих пор, выполнив следующий блок кода всего за 3 секунды:

tic; 
    for i=1:10000 result=setdiff(list1,list2,'rows'); 
    end; 
toc 
>> Elapsed time is 2.821303 seconds. 

Однако, если ваш пример набор данных является отражением того факта, что ваши данные являются векторами, целые числа, и в достаточно ограниченном диапазон, то вы можете ускорить работу кожура линейный индекс эквивалент вместо триплета с помощью sub2ind, например:

range=max_value_outer*ones(1,3); 
[c,ia] = setdiff(sub2ind(range,List1(:,1),List1(:,2),List1(:,3)), sub2ind(range,List2(:,1),List2(:,2),List2(:,3))); result=List1(ia,:); 
    result=List1(ia,:); 

Если вы бежите, что 10000 раз по сравнению с прямым setdiff по строкам, вы получите этот

tic; 
for i=1:10000 
    range=max_value_outer*ones(1,3); 
    [c,ia] = setdiff(sub2ind(range,List1(:,1),List1(:,2),List1(:,3)), sub2ind(range,List2(:,1),List2(:,2),List2(:,3))); 
    result=List1(ia,:); 
end; 
toc 
>> Elapsed time is 2.285992 seconds. 

Так падение% 20 или около того во время выполнения из setdiff (,, 'row) и около 98% от реализации цикла цикла (не показано). В зависимости от того, как выглядят ваши данные, я могу придумать несколько идей, которые могут ускорить процесс. Например, если максимальное значение, которое вы рассматриваете, относительно невелико по сравнению с памятью, вы могли бы воспользоваться линейной индексацией путем сопоставления пространства выборки с памятью, а затем с использованием линейных индексов из набора бит List1 с высоким значением, за которым следует набор из List2 для установки они низкие. Любые биты, которые остались высокими, будут в List1, но не в List2. Существует упрощенная версия этого here, хотя я не ручаюсь за эту реализацию.

Надеюсь, что это поможет!

Смежные вопросы