1. ホーム
  2. c++

[解決済み] c++11のSequence-zip関数?

2022-08-06 12:54:35

質問

新しい範囲ベースのforループを使うと、次のようなコードを書くことができます。

for(auto x: Y) {}

これは、IMOが 巨大な からの改善です(たとえば)

for(std::vector<int>::iterator x=Y.begin(); x!=Y.end(); ++x) {}

Pythonのように2つ同時にループさせることは可能か? zip 関数のように、2つのループを同時に回すことはできますか?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)

どのように解決するのですか?

警告です。 boost::zip_iterator そして boost::combine は、Boost 1.63.0 (2016 Dec 26) 時点で、入力コンテナの長さが同じでない場合、未定義の動作になります (クラッシュしたり、終わりを越えて反復したりすることがあります)。


Boost 1.56.0 (2014 Aug 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);
    }
}

これは次のように表示されます。

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);
}

使い方は同じです。