2015-03-17 4 views
8

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

DJiSet = [5 7 8];     % elements of which I need the indices 
JiSet = [3 4 5 6 7 8 9 11 12 20]; % vector to search 

Выход здесь будет:

[3 5 6] 

Самый быстрый я придумал до сих пор это:

Output = find(ismember(JiSet,DJiSet)); 

Однако я есть ощущение, что это можно сделать быстрее, тем более, что я думал, что команда find довольно медленная.

Things отметить:

  • Значения в DJiSet гарантированно все присутствовать в JiSet
  • JiSet всегда сортируются в порядке возрастания, без повторных записей
  • Вектор DJiSet не гарантируется можно найти смежно в JiSet

ответ

10

Подход № 1

Вы можете избежать find, поменяв местами DJiSet и JiSet внутри ismember, а затем использовать второй выход, который дает нам совпадающие индексы -

[~,out] = ismember(DJiSet,JiSet) 

Approach # 2

Локальный подход, удовлетворяющий конкретным условиям, установленным в вопросе, может быть опробован, а не конечно, если это будет более эффективно -

intv_idx = zeros(1,numel(DJiSet)); 
intv_idx(1) = find(JiSet==DJiSet(1),1); 
start = intv_idx(1)+1; 
for k = 2:numel(DJiSet) 
    idx = find(JiSet(start:end)==DJiSet(k),1); 
    start = idx+start; 
    intv_idx(k) = idx; 
end 
out = cumsum(intv_idx); 
+2

Ударьте меня на несколько секунд haha ​​+1 –

+1

именно то, что я искал, спасибо! –

+0

Вы? Написание цикла 'for'? Что случилось? – Adriaan

4

Возможно, вы можете попробовать пересечь? Это, предполагают, чтобы быть намного быстрее:

[Intersect,indDJiSet,indJiSet] = intersect(DJiSet,JiSet) 

Порядок не имеет значения, до тех пор, как элемент существует в обоих списке, ДИН элементы дает индекс.

5

Divakar's answer - это путь. Но в случае, если вы хотите сделать это более вручную:

[~, Output] = max(bsxfun(@eq, DJiSet(:).', JiSet(:)), [], 1); 

Это находит первого появления, если есть больше чем один.

Если значения в DJiSet были не гарантированы присутствовать в JiSet, вы могли бы использовать небольшую модификацию:

[val, Output] = max(bsxfun(@eq, DJiSet(:).', JiSet(:))); %' 
Output(~val) = 0; %// 0 indicates "not found" 
5

Для небольших наборов данных, кажется, что мой оригинальный подход был быстрее, чем оба ismember, предложенное Дивакаром и решением intersect, предложенное qmeeeeeee, но все три избили решение Луиса Мендо, используя старые добрые bsxfun. Смотрите ниже код, который раз каждый подход:

function somescript() 

IsmemberTime = timeit(@membersol) 
IntersectTime = timeit(@intersectsol) 
FindTime = timeit(@naivesol) 
BsxTime = timeit(@bsxfunsol) 

    function membersol() 
     rng(1) 
     set = randi(30,[1000 15]);    % generate 1000 vectors of length 15, containing random integers 
     for i=1:1000 
      [~,out] = ismember(set(i,1:5),set(i,6:end));  % first 5 random integers are the values to be found in the remainder of the vector 
     end 

    end 

    function intersectsol() 
     rng(1) 
     set = randi(30,[1000 15]); 
     for i=1:1000 
      [~,~,Output] = intersect(set(i,1:5),set(i,6:end)); 
     end 
    end 

    function naivesol() 
     rng(1) 
     set = randi(30,[1000 15]); 
     for i=1:1000 
      Output = find(ismember(set(i,6:end),set(i,1:5))); 
     end 
    end 

    function bsxfunsol() 
     rng(1) 
     set = randi(30,[1000 15]); 
     for i=1:1000 
      [~, Output] = max(bsxfun(@eq, set(i,1:5).', set(i,6:end)), [], 1); 
     end 
    end 
end 

Который на моей машине (работает R2014b) возвращает следующие тайминги:

IsmemberTime = 

    0.1101 


IntersectTime = 

    0.2008 


FindTime = 

    0.0698 


BsxTime = 

    0.0218 

Это говорит о том, что для небольших наборов данных, по меньшей мере, с помощью find и ismember на инвертированном порядке векторов на самом деле быстрее, чем использование только ismember. Так как есть некоторые фиксированные накладные расходы для всех методов из генерации наборов данных set, которые используются для тестирования, разница кажется довольно большой. Более подробные тесты можно найти в комментариях ниже.

+0

Хороший бенчмаркинг. Вы попробовали мое решение? Кажется, что это быстрее (см. Обновленный код бенчмаркинга [здесь] (http://paste.ofcode.org/38j9dxV5bmvtfKqyXdWRwuW)). Кроме того, Divakar предоставил новый подход в своем ответе –

+0

@ LuisMendo Nope, новый подход кажется более медленным на некоторых быстрых тестах! – Divakar

+0

@ LuisMendo Я имел в виду, что мой новый подход был медленнее :) Ну, вот еще один способ сделать бенчмаркинг, охватывающий все перечисленные подходы, исключая мой новый подход, который медленный время от времени, если только OP не может иметь дело с очень маленьким 'DJiSet' - http: //ideone.com/0LO47t. Похоже, оригинальный подход лучше всего подходит здесь! – Divakar

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