Hoo*_*ked 87 c++ sequences c++11
使用新的基于范围的for循环,我们可以编写类似的代码
for(auto x: Y) {}
Run Code Online (Sandbox Code Playgroud)
哪个IMO是一个巨大的进步(例如)
for(std::vector<int>::iterator x=Y.begin(); x!=Y.end(); ++x) {}
Run Code Online (Sandbox Code Playgroud)
可以用它来循环两个同时循环,比如Pythons zip
函数吗?对于那些不熟悉Python的人,代码如下:
Y1 = [1,2,3]
Y2 = [4,5,6,7]
for x1,x2 in zip(Y1,Y2):
print x1,x2
Run Code Online (Sandbox Code Playgroud)
作为输出 (1,4) (2,5) (3,6)
ken*_*ytm 84
警告: boost::zip_iterator
和boost::combine
作为升压1.63.0(2016年12月26)将导致未定义的行为的,如果输入容器的长度是不相同的(它可能会崩溃或迭代之外的端部).
从Boost 1.56.0(2014年8月7日)开始,您可以使用boost::combine
(该函数存在于早期版本中但未记录):
#include <boost/range/combine.hpp>
#include <vector>
#include <list>
#include <string>
int main() {
std::vector<int> a {4, 5, 6};
double b[] = {7, 8, 9};
std::list<std::string> c {"a", "b", "c"};
for (auto tup : boost::combine(a, b, c, a)) { // <---
int x, w;
double y;
std::string z;
boost::tie(x, y, z, w) = tup;
printf("%d %g %s %d\n", x, y, z.c_str(), w);
}
}
Run Code Online (Sandbox Code Playgroud)
这会打印出来
4 7 a 4 5 8 b 5 6 9 c 6
在早期版本中,您可以自己定义范围,如下所示:
#include <boost/iterator/zip_iterator.hpp>
#include <boost/range.hpp>
template <typename... T>
auto zip(T&&... containers) -> boost::iterator_range<boost::zip_iterator<decltype(boost::make_tuple(std::begin(containers)...))>>
{
auto zip_begin = boost::make_zip_iterator(boost::make_tuple(std::begin(containers)...));
auto zip_end = boost::make_zip_iterator(boost::make_tuple(std::end(containers)...));
return boost::make_iterator_range(zip_begin, zip_end);
}
Run Code Online (Sandbox Code Playgroud)
用法是一样的.
Ale*_* C. 16
您可以使用基于的解决方案boost::zip_iterator
.创建一个假容器类,维护对容器的引用,以及zip_iterator
从begin
和end
成员函数返回的容器.现在你可以写了
for (auto p: zip(c1, c2)) { ... }
Run Code Online (Sandbox Code Playgroud)
示例实现(请测试):
#include <iterator>
#include <boost/iterator/zip_iterator.hpp>
template <typename C1, typename C2>
class zip_container
{
C1* c1; C2* c2;
typedef boost::tuple<
decltype(std::begin(*c1)),
decltype(std::begin(*c2))
> tuple;
public:
zip_container(C1& c1, C2& c2) : c1(&c1), c2(&c2) {}
typedef boost::zip_iterator<tuple> iterator;
iterator begin() const
{
return iterator(std::begin(*c1), std::begin(*c2));
}
iterator end() const
{
return iterator(std::end(*c1), std::end(*c2));
}
};
template <typename C1, typename C2>
zip_container<C1, C2> zip(C1& c1, C2& c2)
{
return zip_container<C1, C2>(c1, c2);
}
Run Code Online (Sandbox Code Playgroud)
我将可变版本作为一个很好的练习留给读者.
Jon*_*ely 15
请参阅<redi/zip.h>
一个zip
与range-base一起工作的函数,它for
接受任意数量的范围,可以是rvalues或lvalues,可以是不同的长度(迭代将在最短范围的末尾停止).
std::vector<int> vi{ 0, 2, 4 };
std::vector<std::string> vs{ "1", "3", "5", "7" };
for (auto i : redi::zip(vi, vs))
std::cout << i.get<0>() << ' ' << i.get<1>() << ' ';
Run Code Online (Sandbox Code Playgroud)
打印 0 1 2 3 4 5
aar*_*man 14
所以我在无聊之前写了这个zip,我决定发帖,因为它与其他人不同,因为它不使用boost,看起来更像是c ++ stdlib.
template <typename Iterator>
void advance_all (Iterator & iterator) {
++iterator;
}
template <typename Iterator, typename ... Iterators>
void advance_all (Iterator & iterator, Iterators& ... iterators) {
++iterator;
advance_all(iterators...);
}
template <typename Function, typename Iterator, typename ... Iterators>
Function zip (Function func, Iterator begin,
Iterator end,
Iterators ... iterators)
{
for(;begin != end; ++begin, advance_all(iterators...))
func(*begin, *(iterators)... );
//could also make this a tuple
return func;
}
Run Code Online (Sandbox Code Playgroud)
使用示例:
int main () {
std::vector<int> v1{1,2,3};
std::vector<int> v2{3,2,1};
std::vector<float> v3{1.2,2.4,9.0};
std::vector<float> v4{1.2,2.4,9.0};
zip (
[](int i,int j,float k,float l){
std::cout << i << " " << j << " " << k << " " << l << std::endl;
},
v1.begin(),v1.end(),v2.begin(),v3.begin(),v4.begin());
}
Run Code Online (Sandbox Code Playgroud)
Pav*_*aka 10
从C++23开始,我们可以迭代std::views::zip
. 下面是一个简单的例子。
#include <iostream>
#include <ranges>
#include <vector>
int main() {
std::vector<int> x {4, 5, 6};
double y[] = {7, 8, 9};
for (auto [elem1,elem2] : std::views::zip(x, y))
std::cout << "[" << elem1 << "," << elem2 << "]" << " ";
}
Run Code Online (Sandbox Code Playgroud)
可以在下面验证输出(在线编译器)。不确定该链接存在多少天。
https://godbolt.org/z/KjjE4eeGY
小智 8
使用range-v3:
#include <range/v3/all.hpp>
#include <vector>
#include <iostream>
namespace ranges {
template <class T, class U>
std::ostream& operator << (std::ostream& os, common_pair<T, U> const& p)
{
return os << '(' << p.first << ", " << p.second << ')';
}
}
using namespace ranges::v3;
int main()
{
std::vector<int> a {4, 5, 6};
double b[] = {7, 8, 9};
std::cout << view::zip(a, b) << std::endl;
}
Run Code Online (Sandbox Code Playgroud)
输出:
[(4,7),(5,8),(6,9)]
小智 8
std :: transform可以做到这一点:
std::vector<int> a = {1,2,3,4,5};
std::vector<int> b = {1,2,3,4,5};
std::vector<int>c;
std::transform(a.begin(),a.end(), b.begin(),
std::back_inserter(c),
[](const auto& aa, const auto& bb)
{
return aa*bb;
});
for(auto cc:c)
std::cout<<cc<<std::endl;
Run Code Online (Sandbox Code Playgroud)
如果第二个序列较短,我的实现似乎给出了默认的初始化值.
如果您喜欢运算符重载,这里有三种可能性。前两个分别使用std::pair<>
和std::tuple<>
作为迭代器;第三个将其扩展到基于范围的for
. 请注意,并非每个人都会喜欢这些运算符的定义,因此最好将它们保存在单独的命名空间中,并using namespace
在要使用它们的函数(而不是文件!)中放置一个。
#include <iostream>
#include <utility>
#include <vector>
#include <tuple>
// put these in namespaces so we don't pollute global
namespace pair_iterators
{
template<typename T1, typename T2>
std::pair<T1, T2> operator++(std::pair<T1, T2>& it)
{
++it.first;
++it.second;
return it;
}
}
namespace tuple_iterators
{
// you might want to make this generic (via param pack)
template<typename T1, typename T2, typename T3>
auto operator++(std::tuple<T1, T2, T3>& it)
{
++( std::get<0>( it ) );
++( std::get<1>( it ) );
++( std::get<2>( it ) );
return it;
}
template<typename T1, typename T2, typename T3>
auto operator*(const std::tuple<T1, T2, T3>& it)
{
return std::tie( *( std::get<0>( it ) ),
*( std::get<1>( it ) ),
*( std::get<2>( it ) ) );
}
// needed due to ADL-only lookup
template<typename... Args>
struct tuple_c
{
std::tuple<Args...> containers;
};
template<typename... Args>
auto tie_c( const Args&... args )
{
tuple_c<Args...> ret = { std::tie(args...) };
return ret;
}
template<typename T1, typename T2, typename T3>
auto begin( const tuple_c<T1, T2, T3>& c )
{
return std::make_tuple( std::get<0>( c.containers ).begin(),
std::get<1>( c.containers ).begin(),
std::get<2>( c.containers ).begin() );
}
template<typename T1, typename T2, typename T3>
auto end( const tuple_c<T1, T2, T3>& c )
{
return std::make_tuple( std::get<0>( c.containers ).end(),
std::get<1>( c.containers ).end(),
std::get<2>( c.containers ).end() );
}
// implement cbegin(), cend() as needed
}
int main()
{
using namespace pair_iterators;
using namespace tuple_iterators;
std::vector<double> ds = { 0.0, 0.1, 0.2 };
std::vector<int > is = { 1, 2, 3 };
std::vector<char > cs = { 'a', 'b', 'c' };
// classical, iterator-style using pairs
for( auto its = std::make_pair(ds.begin(), is.begin()),
end = std::make_pair(ds.end(), is.end() ); its != end; ++its )
{
std::cout << "1. " << *(its.first ) + *(its.second) << " " << std::endl;
}
// classical, iterator-style using tuples
for( auto its = std::make_tuple(ds.begin(), is.begin(), cs.begin()),
end = std::make_tuple(ds.end(), is.end(), cs.end() ); its != end; ++its )
{
std::cout << "2. " << *(std::get<0>(its)) + *(std::get<1>(its)) << " "
<< *(std::get<2>(its)) << " " << std::endl;
}
// range for using tuples
for( const auto& d_i_c : tie_c( ds, is, cs ) )
{
std::cout << "3. " << std::get<0>(d_i_c) + std::get<1>(d_i_c) << " "
<< std::get<2>(d_i_c) << " " << std::endl;
}
}
Run Code Online (Sandbox Code Playgroud)
我独立地遇到了同样的问题,并不喜欢上述任何一种语法.所以,我有一个简短的头文件,基本上与boost zip_iterator相同,但有一些宏,使语法更适合我:
https://github.com/cshelton/zipfor
例如,你可以做到
vector<int> a {1,2,3};
array<string,3> b {"hello","there","coders"};
zipfor(i,s eachin a,b)
cout << i << " => " << s << endl;
Run Code Online (Sandbox Code Playgroud)
主要的语法糖是我可以命名每个容器中的元素.我还包括一个"mapfor",它执行相同的操作,但是对于map(命名元素的".first"和".second").
// declare a, b
BOOST_FOREACH(boost::tie(a, b), boost::combine(list_of_a, list_of_b)){
// your code here.
}
Run Code Online (Sandbox Code Playgroud)
如果您有一个符合 C++14 的编译器(例如 gcc5),您可以使用Ryan Hainingzip
提供的库,它看起来非常有前途:cppitertools
array<int,4> i{{1,2,3,4}};
vector<float> f{1.2,1.4,12.3,4.5,9.9};
vector<string> s{"i","like","apples","alot","dude"};
array<double,5> d{{1.2,1.2,1.2,1.2,1.2}};
for (auto&& e : zip(i,f,s,d)) {
cout << std::get<0>(e) << ' '
<< std::get<1>(e) << ' '
<< std::get<2>(e) << ' '
<< std::get<3>(e) << '\n';
std::get<1>(e)=2.2f; // modifies the underlying 'f' array
}
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
44949 次 |
最近记录: |