C++11 的序列压缩函数?
使用新的基于范围的 for 循环,我们可以编写如下代码:
for(auto x: Y) {}
Which IMO is a 巨大 改进 from (例如)
for(std::vector<int>::iterator x=Y.begin(); x!=Y.end(); ++x) {}
它可以用于循环两个同时循环,就像 Python 的 zip
函数?对于那些不熟悉 Python 的人,代码:
Y1 = [1, 2, 3]
Y2 = [4, 5, 6, 7]
for x1,x2 in zip(Y1, Y2):
print(x1, x2)
给出输出 (1,4) (2,5) (3,6)
With the new range-based for-loop we can write code like:
for(auto x: Y) {}
Which IMO is a huge improvement from (for ex.)
for(std::vector<int>::iterator x=Y.begin(); x!=Y.end(); ++x) {}
Can it be used to loop over two simultaneous loops, like Python's zip
function? For those unfamiliar with Python, the code:
Y1 = [1, 2, 3]
Y2 = [4, 5, 6, 7]
for x1,x2 in zip(Y1, Y2):
print(x1, x2)
Gives as output (1,4) (2,5) (3,6)
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(16)
警告:从 Boost 1.63.0(2016 年 12 月 26 日)开始,
boost::zip_iterator
和boost::combine
将导致未定义的行为,如果长度输入容器的数量不相同(它可能会崩溃或迭代到末尾)。从 Boost 1.56.0(2014 年 8 月 7 日)开始,您可以use
boost::combine
(该函数存在于早期版本中,但未记录):这将打印
在早期版本中,您可以自己定义一个范围,例如this:
用法是一样的。
Warning:
boost::zip_iterator
andboost::combine
as of Boost 1.63.0 (2016 Dec 26) will cause undefined behavior if the length of the input containers are not the same (it may crash or iterate beyond the end).Starting from Boost 1.56.0 (2014 Aug 7) you could use
boost::combine
(the function exists in earlier versions but undocumented):This would print
In earlier versions, you could define a range yourself like this:
The usage is the same.
std::transform 可以简单地做到这一点:
如果第二个序列较短,我的实现似乎给出了默认的初始化值。
std::transform can do this trivially:
If the second sequence is shorter, my implementation seems to be giving default initialized values.
所以我之前在无聊的时候写了这个zip,我决定发布它,因为它与其他的不同,它不使用boost并且看起来更像c++ stdlib。
使用示例:
So I wrote this zip before when I was bored, I decided to post it because it's different than the others in that it doesn't use boost and looks more like the c++ stdlib.
Example use:
使用 range-v3:
输出:
With range-v3:
The output:
请参阅
用于zip
函数,该函数与基于范围的for
一起使用,并接受任意数量的范围,可以是右值或左值,并且可以是不同的长度(迭代会停在最后最短范围)。打印
0 1 2 3 4 5
See
<redi/zip.h>
for azip
function which works with range-basefor
and accepts any number of ranges, which can be rvalues or lvalues and can be different lengths (iteration will stop at the end of the shortest range).Prints
0 1 2 3 4 5
您可以使用基于
boost::zip_iterator
的解决方案。创建一个虚假容器类,维护对容器的引用,并从begin
和end
成员函数返回zip_iterator
。现在您可以编写示例实现(请测试):
我将可变参数版本作为一个很好的练习留给读者。
You can use a solution based on
boost::zip_iterator
. Make a phony container class maintaining references to your containers, and which returnzip_iterator
from thebegin
andend
member functions. Now you can writeExample implementation (please test):
I leave the variadic version as an excellent exercise to the reader.
从C++23开始,我们可以迭代
std::views::zip
。下面是一个简单的例子。
可以在下面验证输出(在线编译器)。不确定该链接存在多少天。
https://godbolt.org/z/KjjE4eeGY
From C++23, we can iterate on
std::views::zip
.Below is simple example.
The output can be verified below (an online compiler). Not sure how many days the link exists.
https://godbolt.org/z/KjjE4eeGY
如果您喜欢运算符重载,这里有三种可能性。前两个分别使用
std::pair<>
和std::tuple<>
作为迭代器;第三个将其扩展为基于范围的for
。请注意,并不是每个人都会喜欢这些运算符的定义,因此最好将它们保存在单独的命名空间中,并在您想要使用这些的函数(而不是文件!)中拥有一个using 命名空间
。If you like operator overloading, here are three possibilities. The first two are using
std::pair<>
andstd::tuple<>
, respectively, as iterators; the third extends this to range-basedfor
. Note that not everyone will like these definitions of the operators, so it's best to keep them in a separate namespace and have ausing namespace
in the functions (not files!) where you'd like to use these.我独立遇到了同样的问题,并且不喜欢上述任何一个的语法。因此,我有一个简短的头文件,其本质上与 boost zip_iterator 相同,但有一些宏使语法对我来说更容易接受:
https ://github.com/cshelton/zipfor
例如,你可以这样做
主要的语法糖是我可以命名每个容器中的元素。我还包括一个具有相同功能的“mapfor”,但用于映射(命名元素的“.first”和“.second”)。
I ran into this same question independently and didn't like the syntax of any of the above. So, I have a short header file that essentially does the same as the boost zip_iterator but has a few macros to make the syntax more palatable to me:
https://github.com/cshelton/zipfor
For example you can do
The main syntactic sugar is that I can name the elements from each container. I also include a "mapfor" that does the same, but for maps (to name the ".first" and ".second" of the element).
如果您有 C++14 兼容编译器(例如 gcc5),您可以使用
cpitertools
库,由 Ryan Haining 开发,看起来非常有前途:If you have a C++14 compliant compiler (e.g. gcc5) you can use
zip
provided in thecppitertools
library by Ryan Haining, which looks really promising:对于 C++ 流处理库 我正在编写我一直在寻找一种不依赖第三方库并可与任意数量的容器一起使用的解决方案。我最终得到了这个解决方案。它类似于使用 boost 的公认解决方案(如果容器长度不相等也会导致未定义的行为)
For a C++ stream processing library I'm writing I was looking for a solution that doesn't rely on third party libraries and works with an arbitrary number of containers. I ended up with this solution. It's similar to the accepted solution which uses boost (and also results in undefined behavior if the container lengths are not equal)
对 aaronman 的解决方案的改进:
for_each_arg()< /代码>
。
请参阅在 GodBolt 上的工作。
An improvement on aaronman's solution:
for_each_arg()
.See it working on GodBolt.
我会推荐这个。我发现它非常优雅,并且正是我(和您)所需要的。
https://github.com/CommitThis/zip-iterator
以防万一,这里有一个代码副本。请注意,它是在 MIT 许可证下分发的,也不要忘记注明作者姓名。
zip.hpp
示例
I would propose this one. I found it to be quite elegant, and exactly what I (and you) needed.
https://github.com/CommitThis/zip-iterator
Just in case here's a code copy. Note, it is distributed under MIT License, also don't forget to put name of author.
zip.hpp
Example
Boost.Iterators 有
zip_iterator
< /a> 您可以使用(文档中的示例)。它不适用于 range for,但您可以使用 std::for_each 和 lambda。Boost.Iterators has
zip_iterator
you can use (example's in the docs). It won't work with range for, but you can usestd::for_each
and a lambda.这是一个不需要 boost 的简单版本。它不会特别有效,因为它创建临时值,并且它不会泛化到列表以外的容器,但它没有依赖项,并且解决了最常见的压缩情况。
尽管其他版本更灵活,但使用列表运算符的目的通常是制作简单的单行代码。该版本的优点是常见情况很简单。
Here is a simple version that does not require boost. It won't be particularly efficient as it creates temporary values, and it does not generalise over containers other than lists, but it has no dependencies and it solves the most common case for zipping.
Although the other versions are more flexible, often the point of using a list operator is make a simple one-liner. This version has the benefit that the common-case is simple.