【问题标题】:Find elements meeting any of a number of criteria查找满足任何条件的元素
【发布时间】:2015-03-17 14:31:06
【问题描述】:

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

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 中连续找到

【问题讨论】:

    标签: matlab


    【解决方案1】:

    方法#1

    您可以通过颠倒DJiSet 和JiSet 在ismember 中的位置来避免find,然后使用为我们提供匹配索引的第二个输出 -

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

    方法 #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);
    

    【讨论】:

    • 比我快几秒哈哈+1
    • 你?编写for 循环?发生了什么?
    • @Adriaan 我猜是那些黑暗的日子之一 :)
    【解决方案2】:

    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"
    

    【讨论】:

      【解决方案3】:

      对于小型数据集,我原来的方法似乎比 Divakar 提出的 ismember 解决方案和 qmeeeeeee 提出的 intersect 解决方案都快,但所有这三个都被 Luis Mendo 的解决方案击败使用好旧的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 的所有方法也有一些固定开销,因此差异似乎很大。更彻底的测试可以在下面的 cmets 中找到。

      【讨论】:

      • 不错的基准测试。你试过我的解决方案了吗?它似乎更快(请参阅更新的基准测试代码here)。此外,Divakar 在他的回答中提供了一种新方法
      • @LuisMendo 不,新方法在一些快速测试中似乎更慢!
      • @LuisMendo 我的意思是我的新方法速度较慢 :) 好吧,这是另一种方法来进行基准测试,涵盖所有列出的方法,不包括我的新方法,它有时很慢,除非 OP 可能正在处理一个非常小DJiSet - ideone.com/0LO47t。似乎原始方法最适合这里!
      • This one 涵盖所有方法。 This one 具有更大的数据大小,涵盖了除 bsxfun 之外的所有内容,因为它在这种情况下内存不足。提议的[~,out] = ismember(DJiSet,JiSet) 看起来还不错!不过对于小数据量,bsxfun 可能是一个不错的选择!
      • @Divakar @LuisMendo 感谢您的密集测试!就我而言,DJiSet 和 JiSet 往往都是非常短的向量(通常少于 10 个条目)。该代码用于分布式机器人计算,其中JiSet 确定机器人i 的本地邻域,DJiSet 是该集合“边界”上的机器人。由于我必须为每个机器人 i 运行此代码并进行大约 6e5 次迭代,因此即使是很小的收益也是非常值得的。对于这么短的向量,bsxfun 确实似乎最快。我会相应地更新我的答案,包括添加的时间。感谢您的帮助!
      【解决方案4】:

      也许你可以尝试相交?应该会快很多:

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

      排序无所谓,只要元素同时存在于两个list中,ind元素都会给出索引。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2012-10-01
        • 1970-01-01
        • 2017-08-09
        • 2018-08-23
        • 2012-01-14
        • 2020-06-19
        • 2013-03-06
        • 2019-01-22
        相关资源
        最近更新 更多