查找符合多个条件的元素

时间:2015-03-17 14:31:06

标签: matlab

我试图在向量中找到与另一个向量对应的元素索引,最好不使用循环。例如,我的输入可能是:

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命令相当慢。

注意事项:

  • DJiSet
  • 中保证JiSet中的值都存在
  • JiSet始终按升序排序,无需重复输入
  • 无法保证在DJiSet
  • 中连续找到向量JiSet

4 个答案:

答案 0 :(得分:10)

方法#1

您可以通过在find内反转DJiSetJiSet的位置来避免ismember,然后使用第二个输出来为我们提供匹配的索引 -

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

方法#2

可以尝试满足问题中设定的特定条件的Loopy方法,但不确定这是否会更有效 -

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

答案 1 :(得分:5)

Divakar's answer是要走的路。但是如果你想手动更多的话:

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

如果有多个,则会找到第一个

如果DJiSetJiSet中的值无法保证出现在[val, Output] = max(bsxfun(@eq, DJiSet(:).', JiSet(:))); %' Output(~val) = 0; %// 0 indicates "not found" 中,您可以使用一个小修改:

{{1}}

答案 2 :(得分:5)

对于小型数据集,似乎我的原始方法比Divakar提出的ismember解决方案和qmeeeeeee提出的intersect解决方案更快,但所有三个都被打败了通过路易斯·门多的解决方案,使用优秀的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

这表明,对于小数据集,至少在向量的反转顺序上使用findismember实际上比单独使用ismember更快。由于生成用于测试的数据集set的所有方法也有一些固定的开销,因此差异似乎相当大。可以在下面的评论中找到更全面的测试。

答案 3 :(得分:4)

也许你可以试试相交?假设速度要快得多:

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

排序无关紧要,只要元素存在于两个列表中,ind元素就会给出索引。