C ++ 11 용 Sequence-zip 함수?
새로운 범위 기반 for 루프를 사용하면 다음과 같은 코드를 작성할 수 있습니다.
for(auto x: Y) {}
어떤 IMO가 (예를 들어) 크게 개선되었습니다.
for(std::vector<int>::iterator x=Y.begin(); x!=Y.end(); ++x) {}
Pythons 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)
주의 : boost::zip_iterator
및 boost::combine
상기 입력 용기의 길이가 동일하지 않으면 정의되지 않은 동작이 발생할 부스트 1.63.0 (2,016 십이 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);
}
}
이것은 인쇄됩니다
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);
}
사용법은 동일합니다.
.NET 기반 솔루션을 사용할 수 있습니다 boost::zip_iterator
. 컨테이너에 대한 참조를 유지 zip_iterator
하고 begin
및 end
멤버 함수 에서 반환되는 가짜 컨테이너 클래스를 만듭니다 . 이제 쓸 수 있습니다
for (auto p: zip(c1, c2)) { ... }
구현 예 (테스트하십시오) :
#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);
}
나는 가변 버전을 독자에게 훌륭한 연습으로 남겨둔다.
range-base 와 함께 작동하고 rvalue 또는 lvalue 일 수 있고 다른 길이 일 수있는 범위의 수를 허용 <redi/zip.h>
하는 zip
함수를 참조하십시오 for
(반복은 최단 범위의 끝에서 중지됨).
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>() << ' ';
인쇄물 0 1 2 3 4 5
그래서 지루할 때 이전에이 zip을 썼는데, 부스트를 사용하지 않고 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;
}
사용 예 :
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());
}
와 범위-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;
}
출력 :
[(4, 7), (5, 8), (6, 9)]
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;
두 번째 시퀀스가 더 짧으면 내 구현이 기본 초기화 값을 제공하는 것 같습니다.
나는이 같은 질문을 독립적으로 만났고 위의 구문이 마음에 들지 않았습니다. 따라서 기본적으로 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;
주요 구문 설탕은 각 컨테이너에서 요소의 이름을 지정할 수 있다는 것입니다. 또한 동일한 작업을 수행하는 "mapfor"를 포함하지만 맵 (요소의 ".first"및 ".second"이름 지정)을위한 것입니다.
// declare a, b
BOOST_FOREACH(boost::tie(a, b), boost::combine(list_of_a, list_of_b)){
// your code here.
}
연산자 오버로딩을 좋아한다면 여기에 세 가지 가능성이 있습니다. 처음 두 사용 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;
}
}
C ++ 14 호환 컴파일러 (예 : gcc5) zip
가있는 경우 cppitertools
Ryan Haining 이 라이브러리 에서 제공 한 것을 사용할 수 있습니다 . 정말 유망 해 보입니다.
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
}
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)
#include <utility>
namespace impl {
template <typename Iter, typename... Iters>
class zip_iterator {
public:
using value_type = std::tuple<const typename Iter::value_type&,
const typename Iters::value_type&...>;
zip_iterator(const Iter &head, const Iters&... tail)
: head_(head), tail_(tail...) { }
value_type operator*() const {
return std::tuple_cat(std::tuple<const typename Iter::value_type&>(*head_), *tail_);
}
zip_iterator& operator++() {
++head_; ++tail_;
return *this;
}
bool operator==(const zip_iterator &rhs) const {
return head_ == rhs.head_ && tail_ == rhs.tail_;
}
bool operator!=(const zip_iterator &rhs) const {
return !(*this == rhs);
}
private:
Iter head_;
zip_iterator<Iters...> tail_;
};
template <typename Iter>
class zip_iterator<Iter> {
public:
using value_type = std::tuple<const typename Iter::value_type&>;
zip_iterator(const Iter &head) : head_(head) { }
value_type operator*() const {
return value_type(*head_);
}
zip_iterator& operator++() { ++head_; return *this; }
bool operator==(const zip_iterator &rhs) const { return head_ == rhs.head_; }
bool operator!=(const zip_iterator &rhs) const { return !(*this == rhs); }
private:
Iter head_;
};
} // namespace impl
template <typename Iter>
class seq {
public:
using iterator = Iter;
seq(const Iter &begin, const Iter &end) : begin_(begin), end_(end) { }
iterator begin() const { return begin_; }
iterator end() const { return end_; }
private:
Iter begin_, end_;
};
/* WARNING: Undefined behavior if iterator lengths are different.
*/
template <typename... Seqs>
seq<impl::zip_iterator<typename Seqs::iterator...>>
zip(const Seqs&... seqs) {
return seq<impl::zip_iterator<typename Seqs::iterator...>>(
impl::zip_iterator<typename Seqs::iterator...>(std::begin(seqs)...),
impl::zip_iterator<typename Seqs::iterator...>(std::end(seqs)...));
}
Boost.Iterators has zip_iterator
you can use (example's in the docs). It won't work with range for, but you can use std::for_each
and a lambda.
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.
template<class L, class R>
std::list< std::pair<L,R> > zip(std::list<L> left, std::list<R> right)
{
auto l = left.begin();
auto r = right.begin();
std::list< std::pair<L,R> > result;
while( l!=left.end() && r!=right.end() )
result.push_back( std::pair<L,R>( *(l++), *(r++) ) );
return result;
}
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.
참고URL : https://stackoverflow.com/questions/8511035/sequence-zip-function-for-c11
'program tip' 카테고리의 다른 글
그립을 통해서만 크기를 조정할 수있는 테두리없이 WPF 창을 만드는 방법은 무엇입니까? (0) | 2020.09.15 |
---|---|
chrome 또는 firefox를 사용하여 javascript에서 console.trace ()의 결과를 얻는 방법은 무엇입니까? (0) | 2020.09.14 |
단일 Maven 플러그인 실행을 실행 하시겠습니까? (0) | 2020.09.14 |
중첩 된 컨트롤이있는 DesignMode (0) | 2020.09.14 |
주어진 위치에서 목록의 특정 요소를 얻는 방법은 무엇입니까? (0) | 2020.09.14 |