【问题标题】:How do I find the index of the element being passed to the predicate in STL functions?如何找到传递给 STL 函数中谓词的元素的索引?
【发布时间】:2020-06-24 09:02:25
【问题描述】:

考虑以下代码:

    std::vector<int> vec(n);
    for (auto& elem : vec) {
        std::cin >> elem;
    }
    auto count = 0;
    while (!isGood(vec)) {
        auto odd_it = std::find_if(vec.begin(), vec.end(), [] (int num) { return ~(num % 2); });
        auto even_it = std::find_if(vec.begin(), vec.end(), [] (int num) { return num % 2; });
        if(odd_it != vec.end() && even_it != vec.end()) {
            std::swap(vec.at(std::distance(vec.begin(), odd_it)), vec.at(std::distance(vec.begin(), even_it)));
            count++;
        }
        else {
            count = -1;
            break;
        }
    }

(我知道它不是完整的代码,但足以重现问题)

在这段代码中,auto odd_it(以及auto even_it)行将返回向量中的第一个奇数元素。但是,我希望 std::find_if 向我返回一个迭代器,该迭代器指向第一个奇数元素,它也有一个偶数索引(在这种情况下,巧合的是,它也是第一个奇数元素。)

所以,简而言之,问题基本上是找到函数当前正在“处理”的元素的索引(已传递给谓词)

【问题讨论】:

  • 你不能用std::find_if以简单优雅的方式做到这一点。从技术上讲,您可以(通过减去地址),但您最好为此功能编写自己的 find_if
  • 你的意思是像auto odd_it = std::find_if(vec.begin(), vec.end(), [] (int num) { static bool isOdd = true; isOdd = !isOdd; return ~(num % 2) &amp;&amp; isOdd; });
  • 它将返回索引是奇数还是偶数。每次调用谓词时都会翻转标志isOdd,并且感谢static,它的值将在谓词调用之间保留。但我怀疑该标准是否保证严格按顺序调用谓词。但是,任何合理的实施都可以做到。不过,特殊功能似乎是更好的解决方案。
  • horrible example。顺便说一句,C++ 标准库不是 STL。 STLhas gone.
  • “按顺序调用谓词” 是的,在您的机器上,在周三的这种情况下,启用了 degging,没有优化。未定义行为的有趣部分是它看起来可以正常工作。如果不设置 ExecutionPolicy,如果在不同的 CPU 上并行检查每个条件,甚至会导致更多的竞争条件。

标签: c++ predicate c++-standard-library


【解决方案1】:

在 C++17 及以下版本中最明确的解决方案是编写您自己的 find_if 版本,将索引传递给谓词。实现很简单:

template<class Input_it, class Predicate>
Input_it find_if_with_index(Input_it first, Input_it last, Predicate p) {
    for (std::size_t i = 0; first != last; ++i, ++first) {
        if (p(i, *first))
            return first;
    }
    return last;
}

【讨论】:

  • 另外,顺便说一句,在你linked 的示例中,因为在引用上使用&amp; 运算符什么时候返回引用指向的对象的地址?我不太明白...
  • @d4rk4ng31,我猜从 C++ 的一开始。 :)
  • 嗯.. 我居然不知道 ?。那么引用和指针之间的唯一区别是防止内存泄漏和不同的语法? :)
  • 有很多不同之处,任何好书/教程都会阐明,就像在 SO 上搜索一样。
  • @d4rk4ng31,您也可以使用引用泄漏内存:int&amp; i = *new int;
【解决方案2】:

或者,要获取索引,您可以创建自定义迭代器以仅在奇数索引上进行迭代。

使用range-v3,您可以这样做:

auto odd_index_even_value = vec | ranges::view::stride(2)
                                | ranges::view::filter([](int e){ return e % 2 == 0; });
auto even_index_odd_value = vec | ranges::view::drop(1) | ranges::view::stride(2)
                                | ranges::view::filter([](int e){ return e % 2 == 1; });

auto it1 = begin(odd_index_even_value);
auto it2 = begin(even_index_odd_value);

int count = 0;
while (it1 != end(odd_index_even_value) && it2 != end(even_index_odd_value)) {
    std::swap(*it1, *it2);
    ++it1;
    ++it2;
    ++count;
}
if (it1 != end(odd_index_even_value) || it2 != end(even_index_odd_value)) {
    count = -1;   
}

Demo

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多