当前位置: 首页 > 知识库问答 >
问题:

使用C 20在相等的范围内迭代

罗烨霖
2023-03-14

我想知道C 20范围是否有一些很好的方法让我在排序容器的相等范围内(或者在一般情况下任何排序范围)进行迭代。

我有这个有效的“手动”解决方案,但从某种意义上说它并不好,因为它不是真正可组合的(我没有返回一些等范围视图,我只是提供要调用的函数)。

#include <vector>
#include <ranges>
#include <iostream>
#include <fmt/ranges.h>


template<typename Cont, typename Fn>
void for_each_equal_range(const Cont& cont, Fn fn){
    auto current_begin = cont.begin();
    while(true){
        if (current_begin==cont.end()){
            return;
        }
        auto [eq_begin, eq_end] = std::equal_range(current_begin, cont.end(),   *current_begin);
        fn(eq_begin, eq_end);
        current_begin = eq_end;
    }
}

int main() {
    std::vector vals {1,2,2,3,3,3,47};
    for_each_equal_range(vals, [](const auto b, const auto e){
        std::cout << "size: " << std::distance(b,e) << std::endl;
        std::ranges::subrange elems(b, e);
        std::cout << fmt::format("{}",elems) << std::endl;
    });
}

我希望我有这样的东西:

vals | equal_range_split | std::ranges::for_each(...);

如果有一些混淆,这里的范围是什么意思:

  • 等范围好旧STLequal_range意思
  • range是C 20范围库。

我还知道C 20有std::ranges::equal_range算法,但它似乎对我的用例没有太大帮助。

共有2个答案

夹谷俊远
2023-03-14

在C 20中,管道运算符尚未定义std::范围::equal_rangestd::范围::for_each

  for (int global = *vals.begin() - 1 ; 
           auto val : vals | std::ranges::views::filter([&](auto value){return value != global ;}))
    {
        std::ranges::for_each(std::ranges::equal_range(vals, val), [](auto& x){ std::cout << x << std::endl; });
        global = val;
    }
微生德运
2023-03-14

不完全是你要找的,但是如果你有一个协程生成器模板,比如

using namespace std::ranges;

template<typename Range, typename Compare = std::less>
generator<subrange<iterator_t<Range>>> equal_ranges(Range&& range, Compare compare = {}) {
    for (auto current_begin = cont.begin(); current_begin != cont.end();) {
        auto [eq_begin, eq_end] = std::equal_range(current_begin, cont.end(), *current_begin, compare);
        co_yield { eq_begin, eq_end };
        current_begin = eq_end;
    }
}

template<typename Compare>
struct equal_ranges_holder {
    Compare compare;
};

template<typename Compare = std::less>
equal_ranges_holder<Compare> equal_ranges(Compare compare = {}) { return { compare }; } 

template<typename Range, typename Compare>
auto operator|(Range&& range, equal_ranges_holder<Compare> holder) {
    return equal_ranges(range, holder.compare);
}

或者,创建一个单程< code>equal_range_view也相当简单。

using namespace std::ranges;

template<borrowed_range Range, std::strict_weak_order Compare = std::less>
class equal_range_view : public view_interface<equal_range_view> {
    using base_iterator = iterator_t<Range>;
    using base_sentinel = sentinel_t<Range>;

    Range range;
    Compare compare;
public:
    class sentinel {};

    class iterator {
        base_iterator base;
        base_sentinel end;
        Compare compare;
    public:
        using value_type = subrange<base_iterator>;
        using reference = value_type;
        using pointer = value_type *;
        using difference_type = std::ptrdiff_t;
        using iterator_category = std::input_iterator_tag;
    
        equal_range_iterator(base_iterator base, base_sentinel end, Compare compare) : base(base), end(end), compare(compare) {}

        reference operator*() {
            auto [first, last] = std::equal_range(base, end, compare);
            return { first, last };
        }
    
        iterator& operator++() {
            auto [_, last] = std::equal_range(base, end, compare);
            base = last;
            return *this;
        }

        bool operator==(sentinel) const {
            return base == end;
        }
        bool operator!=(sentinel) const {
            return base != end;
        }
    }; 

    explicit equal_range_view(Range range, Compare compare = {}) : range(range), compare(compare) {}

    iterator begin() { return { range.begin(), range.end(), compare }; }
    sentinel end() { return {}; }
};
 类似资料:
  • 问题内容: Swift 2.2可以实现以下功能: 使用3.0,我们会收到以下错误: 类型“范围”(又名“范围”)不符合协议“序列” 我正在尝试对字符串进行快速的非常简单的操作-只需遍历字符串的前半部分(或更常见的问题:遍历字符串的范围)。 我可以执行以下操作: 但是这里我并没有真正遍历字符串。所以问题是:如何遍历给定字符串的范围。喜欢: 问题答案: 您可以使用以下属性来遍历字符串: 从“ 字符串和

  • 有一个非常常见且简单的任务是在两个方向上通过某个范围进行循环迭代: 上面的代码运行完美,但我花了大约一个小时试图摆脱双重检查。 有没有办法解决如果没有如果?也许是一句话?

  • 我是一个角度开发人员和新的反应,这是简单的反应组件,但不工作 错误:在JSX作用域中使用JSX React/React时,“React”必须在作用域中

  • 我有一个Nx2矩阵,例如: 我需要创建一个Nx3矩阵,它以以下方式反映第一个矩阵中的行之间的关系: 使用右列标识范围边界的候选对象,条件为value 此条件适用于矩阵: 到目前为止,我提出了“M[M[:,1] 到目前为止我想到的是:np。差异(M[:,0]) 这就是我被困的地方。我想用这个条件来定义一个范围的上下边界。例如: 最后,回到第一个矩阵,我想为边界内(包括边界)的每个范围添加右列值。 所

  • 对于我的Java类,我正在编写一个小程序,首先选择一个介于1和100之间的数字。然后,它会提示用户开始猜测正确的。如果用户对的猜测过高或过低,程序会打印出一个新范围,供他们在该范围内进行猜测。如果用户输入或,程序只需重新要求用户输入,但不会以任何方式更改范围。 示例输出(当机密号为20时)如下所示: 该项目似乎已经基本完成,但只有一个例外。其中一个要求是,当用户键入的超出我们给定的1和100范围时

  • 问题内容: 我想知道为什么在 i 变量下面的代码中 仍然显示“ 5” 而不是显示 “ 1” 然后 “ 2” 然后 “ 3” ,依此类推?必须是一个范围问题,但由于在全局和dom范围中更改了i变量的范围,但仍然遇到相同的问题,因此我并没有真正了解它。当我提醒 我 的AJAX功能外,它工作得很好。 这是小提琴 编辑: 我选择了 @Tushar Gupta 解决方案,因为它最适合我的需要,但是又遇到了另

  • 我想为一些地图实现编写一个基准测试,包括一个自定义实现。我想测试它在广泛的输入范围内的平均行为。 因为这是我第一次使用JMH,所以使用@Param看起来是显而易见的选择。但事实证明,JMH不会在一个基准测试中使用所有这些不同的输入,而是会为每一组参数运行单独的基准测试。 是否有一些我缺少的功能,或者只是在我的基准测试中循环输入的范围,这是正确的做法? 更新: 我实现了2个不同的基准,给出了完全相反

  • 我编写了一个会话范围的托管bean,用于在domino xpages应用程序中缓存sesion用户特定的信息,如下代码所示: 然后,我在faces配置中声明了它,使其成为会话范围的bean: 在测试bean时,我通过#{NBUser.fullUserName}使用它,它并不总是返回当前domino http会话上下文的用户,例如,我首先由用户“user1”登录并注销,然后由user2登录,bean