【问题标题】:Using std::find_if with std::vector to find smallest element greater than some value使用 std::find_if 和 std::vector 来查找大于某个值的最小元素
【发布时间】:2018-05-17 02:34:20
【问题描述】:

我有一个有序的双精度向量。

std::vector<double> vec;
for(double x{0.0}; x < 10.0 + 0.5; x += 1.0) vec.push_back(x);

我正在尝试使用std::find_if 来查找y &lt; element 所在向量的第一个元素及其对应的索引。其中y 是一些价值。

例如,如果y = 5.5,则相关元素是元素6.0,其索引为6,是第7个元素。

我怀疑可以使用 lambda 函数来做到这一点。

  • 可以使用 lambda 函数来执行此操作吗?

  • 如果是这样,我该如何实现find_if 语句来做我想做的事?

【问题讨论】:

    标签: c++ c++11 vector lambda


    【解决方案1】:

    如果使用 lambda 函数,则需要 1 行代码:x 是本地双精度数(我们正在搜索的值)const double x = 5.5

    std::find_if(vec.cbegin(), vec.cend(), [x] (double element) { return (x < element); })
    

    分解后,我们有:

    std::find_if(vec.cbegin(), vec.cend(), lambda)
    

    lambda 是:

    [x] (double element) { return (x < element); }
    

    这意味着:

    • 捕获局部变量 x 以在 lambda 主体内使用
    • lambda 函数将单个 double 作为参数(find_if 算法将在遍历向量时将每个元素作为 element 传递给此函数)
    • 当找到x &lt; element的第一个元素时,函数体返回true

    注意:我在研究可能的解决方案时自己回答了这个问题。我在自己的程序中使用它的上下文略有不同。在我的上下文中,向量是数值边界的规范,我正在寻找lower &lt; x &lt; higher。因此,我使用的代码与此略有不同,因为我必须将返回的迭代器移动 1 位,因为如何指定数字边界。如果我在转录解决方案时引入了错误,请告诉我。

    【讨论】:

    • 请注意,std::find_if 返回一个迭代器。为了获取索引,您可以使用std::distance(vec.cbegin(), it),这是向量的随机访问迭代器的 O(1) 操作(但如果将向量更改为例如 std::list,则为 O(n)。
    【解决方案2】:

    如果需要索引,可以添加计数器。

    类似

    x = 5;
    
    cnt = -1;
    
    std::find_if(vec.cbegin(), vec.cend(),
       [&] (double element) { ++cnt; return (x < element); })
    

    【讨论】:

    • 这不能保证工作,并且有开销。 std::distance 更可取。
    • @OphirGvirtzer - 你为什么说这不能保证工作?你认为std::distance 更适合std::vector(O(1) 在哪里)还是std::list(O(n) 在哪里)?
    【解决方案3】:

    看起来你还没有被介绍给std::upper_bound

    std::upper_bound(vec.begin(), vec.end(), x);
    

    【讨论】:

      【解决方案4】:

      只需使用std::upper_bound() - 它更有效(它使用二进制搜索)并且不需要 lambda:

      auto it = std::upper_bound( vec.begin(), vec.end(), x );
      

      如果你需要找到lower &lt; x &lt; upper,你可以使用std::equal_range(),但是你需要额外的逻辑来找到正确的lower,因为std::lower_bound会给出小于或等于x的元素,所以你需要确保 lower 小于 x 并且不等于。

      live example

      【讨论】:

        猜你喜欢
        • 2019-02-05
        • 1970-01-01
        • 2018-01-11
        • 1970-01-01
        • 1970-01-01
        • 2014-02-09
        • 2019-07-30
        • 1970-01-01
        • 2012-08-14
        相关资源
        最近更新 更多