【问题标题】:Slice view for C++20 rangesC++20 范围的切片视图
【发布时间】:2019-06-17 20:27:45
【问题描述】:

Python 的itertools 有一个islice(seq, start, stop, step) 过程,它接受一个序列并返回一个迭代器,该迭代器是startstop 之间序列值的每个stepth 值。

C++20 的 Ranges 库是否提供类似的功能,例如像slice 这样的函数,它接受一个随机访问迭代器start、一个标记stop 和一个步长值step,并返回一个随机访问迭代器,该迭代器对step 之间的每个stepth 值进行迭代startstop?

如果没有,可以使用 Ranges 库提供的原语来实现这样的迭代器适配器吗?

(我知道如何手动实现这样的适配器,所以这不是问题。)

【问题讨论】:

  • range-v3 有stride_viewspan 可以组合成相同的效果。我不知道 C++20 是否有所有的 range-v3。

标签: c++ stl slice c++20


【解决方案1】:

不完全是。

C++20 将具有view::iota,它为您提供从起始值到标记的序列。但是,它没有跨步功能。它只会增加(通过++)。

但是,您可以将其与range-v3's view::stride 结合使用以添加步骤。那就是:

auto evens = view::iota(0, 100) | view::stride(2); // [0, 2, 4, 6, ... ]

对于现有的范围,有view::slice,它也没有大步前进。但是这些是正交的并且很好地分层:

auto even_teens  = view::iota(0, 100)
                 | view::slice(10, 20)
                 | view::stride(2); // [10, 12, 14, 16, 18]

【讨论】:

  • 确实,view::sliceview::stride 将一起完成我一直在寻找的事情。 (不幸的是,如果这些不包含在 C++ 20 中,我最初的问题的答案是否定的。)是否有关于 range-v3 的 view::sliceview::stride 的任何文档?
  • @Marc 我不这么认为。最好的办法是查看我认为的测试和声明。
【解决方案2】:

不幸的是,Range-v3 中的 slicestride(如 Barry'sanswer 中所示)(尚未)在 C++20 中的 Ranges library 中可用。 但是,您可以通过组合std::views::drop_whilestd::views::take_while 来替换slice。要替换 stride,您可以使用范围适配器 std::views::filter 并将特定的 lambda expression 传递给它。为了像 Barry 的示例那样过滤所有其他元素,我将使用带有 init capture 的有状态 lambda 表达式。您可以将所有内容放在一起来表示[10, 12, 14, 16, 18] 的范围,如下所示:

auto even_teens = std::views::iota(0, 100)
                | std::views::drop_while([](int i) { return i < 10; })
                | std::views::take_while([](int i) { return i < 20; })
                | std::views::filter([s = false](auto const&) mutable { return s = !s; });

对于更通用的跨步解决方案,您可以在 lambda 表达式中使用计数器和模运算符。为了能够以可读的方式指定步幅大小n,我将使用以下 lambda 表达式,它提供了另一个跟踪步幅操作的 lambda 表达式:

auto stride = [](int n) {
    return [s = -1, n](auto const&) mutable { s = (s + 1) % n; return !s; };
};

总而言之,最终的解决方案是这样的:

auto even_teens = std::views::iota(0, 100)
                | std::views::drop_while([](int i) { return i < 10; })
                | std::views::take_while([](int i) { return i < 20; })
                | std::views::filter(stride(2));

Code on Wandbox

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2022-11-07
    • 2021-04-11
    • 1970-01-01
    • 1970-01-01
    • 2021-01-14
    • 2019-05-16
    • 2021-06-22
    • 2022-11-02
    相关资源
    最近更新 更多