두 개 이상의 컨테이너를 동시에 반복하는 가장 좋은 방법은 무엇입니까?
C ++ 11은 컨테이너를 반복하는 여러 방법을 제공합니다. 예를 들면 :
범위 기반 루프
for(auto c : container) fun(c)
std :: for_each
for_each(container.begin(),container.end(),fun)
그러나 같은 크기의 두 개 이상의 컨테이너를 반복하여 다음과 같은 작업을 수행하는 데 권장되는 방법은 무엇입니까?
for(unsigned i = 0; i < containerA.size(); ++i) {
containerA[i] = containerB[i];
}
파티에 늦게. 그러나 나는 수준을 반복 할 것입니다. 그러나 고전적인 for
루프가 아니라 보안 for
에 대한 범위 기반 루프를 사용합니다.
for(unsigned i : indices(containerA)) {
containerA[i] = containerB[i];
}
indices
적용에 대해 (게으른 평가 된) 범위를 반환하는 간단한 래퍼 함수입니다. 구현은 간단하지만 여기에 게시하기에는 너무 길기 때문에 GitHub에서 구현을 사용할 수 있습니다 .
이 코드는 수동 클래식 루프 를 사용하는 것만 큼 효율적for
입니다.
이 패턴이 데이터에서 자주 발생하는 경우 zip
두 개의 시퀀스를 구성하고 쌍을 이룬 요소에 해당하는 튜플 범위를 생성하는 다른 패턴을 사용 하는 것이 좋습니다.
for (auto& [a, b] : zip(containerA, containerB)) {
a = b;
}
의 구현은 독자 zip
를위한 연습으로 잡았지만 indices
.
(C ++ 17 이전에는 대신 다음을 작성해야합니다.)
for (auto items&& : zip(containerA, containerB))
get<0>(items) = get<1>(items);
구체적인 예를 들어,
std::copy_n(contB.begin(), contA.size(), contA.begin())
보다 일반적인 경우 zip_iterator
에는 루프에서 사용할 수있는 범위 기반의 작은 함수와 함께 Boost.Iterator를 사용할 수 있습니다 . 대부분의 경우 다음과 같이 작동합니다.
template<class... Conts>
auto zip_range(Conts&... conts)
-> decltype(boost::make_iterator_range(
boost::make_zip_iterator(boost::make_tuple(conts.begin()...)),
boost::make_zip_iterator(boost::make_tuple(conts.end()...))))
{
return {boost::make_zip_iterator(boost::make_tuple(conts.begin()...)),
boost::make_zip_iterator(boost::make_tuple(conts.end()...))};
}
// ...
for(auto&& t : zip_range(contA, contB))
std::cout << t.get<0>() << " : " << t.get<1>() << "\n";
그러나 본격적인들이 제네릭을 위해,은 아마 더 당신 같은 것을 원하는 이 멤버가없는 배열과 user-정의 형식에 대해 올바르게 작동합니다, begin()
/ end()
그러나 않는 이 begin
/ end
자신의 네임 스페이스 기능을. user-가 또한 기능 현관을 const
통해 구체적으로 액세스 할 수 있습니다 zip_c...
.
그리고 나처럼 멋진 오류 메시지를 옹호 하는 사람이라면 임시 컨테이너가 함수에 전달을 확인하고 멋진 오류 메시지를 출력하는 것을 원할 것입니다 zip_...
.
왜 아무도 없습니까?
auto ItA = VectorA.begin();
auto ItB = VectorB.begin();
while(ItA != VectorA.end() || ItB != VectorB.end())
{
if(ItA != VectorA.end())
{
++ItA;
}
if(ItB != VectorB.end())
{
++ItB;
}
}
추신 : 컨테이너 크기가 일치하지 않는 경우에 문 안에 코드를 넣어야합니다.
에 헤더 제공된대로 여러 컨테이너를 사용하여 특정 작업 을 수행하는 방법 에는 여러 가지 가 algorithm
있습니다. 예를 들어, 여러분이 제공하는 한 예제 std::copy
에서 명시적인 for 루프 대신 사용할 수 있습니다 .
반면에 루프 이외의 여러 컨테이너를 일반적으로 반복하는 기본 제공 방법은 없습니다. 때문에 이것은 놀라운 있기 일이 아니다 많은 반복하는 방법은. 생각해 봐. 한 컨테이너를 한 컨테이너를 다른 단계로 반복 할 수 있습니다. 또는 한 용기를 끝까지 통과 한 다음 다른 용기의 끝까지 중단하는 동안 삽입을 시작합니다. 또는 다른 용기를 완전히 통과 한 다음 다시 시작할 때마다 첫 번째 단계의 용기의 한 단계; 또는 다른 패턴; 또는 한 번에 두 개 이상의 용기; 기타 ...
그러나 가장 짧은 컨테이너 길이까지 두 개의 컨테이너를 반복하는 고유 한 "for_each"스타일 함수 를 만들고 다음과 같이 할 수 있습니다.
template <typename Container1, typename Container2>
void custom_for_each(
Container1 &c1,
Container2 &c2,
std::function<void(Container1::iterator &it1, Container2::iterator &it2)> f)
{
Container1::iterator begin1 = c1.begin();
Container2::iterator begin2 = c2.begin();
Container1::iterator end1 = c1.end();
Container2::iterator end2 = c2.end();
Container1::iterator i1;
Container1::iterator i2;
for (i1 = begin1, i2 = begin2; (i1 != end1) && (i2 != end2); ++it1, ++i2) {
f(i1, i2);
}
}
어느 쪽이든 방식으로 원하는 모든 종류의 반복 전략을 만들 수 있습니다.
루프를 직접 수행하는 것이 이와 같은 사용자 지정 함수를 물론 작성하는 것보다 더 많은 것을 주장 할 수 있습니다. 그리고 한두 번만 수행 할 경우 옳습니다. 그러나 좋은 점은 상당히 많은 것이 가능하다는 것입니다. =)
2 개의 컨테이너에서 동시에 반복해야하는 경우 부스트 범위 라이브러리에 표준 for_each 알고리즘의 확장 버전이 있습니다. 예 :
#include <vector>
#include <boost/assign/list_of.hpp>
#include <boost/bind.hpp>
#include <boost/range/algorithm_ext/for_each.hpp>
void foo(int a, int& b)
{
b = a + 1;
}
int main()
{
std::vector<int> contA = boost::assign::list_of(4)(3)(5)(2);
std::vector<int> contB(contA.size(), 0);
boost::for_each(contA, contB, boost::bind(&foo, _1, _2));
// contB will be now 5,4,6,3
//...
return 0;
}
하나의 알고리즘에서 2 개 이상의 컨테이너를 처리해야하는 경우 zip을 사용합니다.
또 다른 솔루션은 람다에서 다른 컨테이너의 반복기 참조를 캡처하고 그에 대해 사후 증분 연산자를 사용하는 것입니다. 예를 들어 간단한 사본은 다음과 같습니다.
vector<double> a{1, 2, 3};
vector<double> b(3);
auto ita = a.begin();
for_each(b.begin(), b.end(), [&ita](auto &itb) { itb = *ita++; })
람다 내부에서 무엇이든 할 수 있으며 ita
증가시킬 수 있습니다. 이것은 여러 용기 케이스로 쉽게 확장됩니다.
범위 라이브러리는이 기능과 기타 매우 유용한 기능을 제공합니다. 다음 예제에서는 Boost.Range 를 사용합니다 . Eric Niebler의 rangev3 는 좋은 대안이 될 것입니다.
#include <boost/range/combine.hpp>
#include <iostream>
#include <vector>
#include <list>
int main(int, const char*[])
{
std::vector<int> const v{0,1,2,3,4};
std::list<char> const l{'a', 'b', 'c', 'd', 'e'};
for(auto const& i: boost::combine(v, l))
{
int ti;
char tc;
boost::tie(ti,tc) = i;
std::cout << '(' << ti << ',' << tc << ')' << '\n';
}
return 0;
}
C ++ 17은 구조화 된 바인딩을 사용하여이를 더욱 향상시킵니다.
int main(int, const char*[])
{
std::vector<int> const v{0,1,2,3,4};
std::list<char> const l{'a', 'b', 'c', 'd', 'e'};
for(auto const& [ti, tc]: boost::combine(v, l))
{
std::cout << '(' << ti << ',' << tc << ')' << '\n';
}
return 0;
}
다음은 하나의 변형입니다.
template<class ... Iterator>
void increment_dummy(Iterator ... i)
{}
template<class Function,class ... Iterator>
void for_each_combined(size_t N,Function&& fun,Iterator... iter)
{
while(N!=0)
{
fun(*iter...);
increment_dummy(++iter...);
--N;
}
}
사용 예
void arrays_mix(size_t N,const float* x,const float* y,float* z)
{
for_each_combined(N,[](float x,float y,float& z){z=x+y;},x,y,z);
}
나도 조금 늦었어요. 그러나 이것을 사용할 수 있습니다 (C 스타일 가변 함수) :
template<typename T>
void foreach(std::function<void(T)> callback, int count...) {
va_list args;
va_start(args, count);
for (int i = 0; i < count; i++) {
std::vector<T> v = va_arg(args, std::vector<T>);
std::for_each(v.begin(), v.end(), callback);
}
va_end(args);
}
foreach<int>([](const int &i) {
// do something here
}, 6, vecA, vecB, vecC, vecD, vecE, vecF);
또는 이것 (함수 매개 변수 팩 사용) :
template<typename Func, typename T>
void foreach(Func callback, std::vector<T> &v) {
std::for_each(v.begin(), v.end(), callback);
}
template<typename Func, typename T, typename... Args>
void foreach(Func callback, std::vector<T> &v, Args... args) {
std::for_each(v.begin(), v.end(), callback);
return foreach(callback, args...);
}
foreach([](const int &i){
// do something here
}, vecA, vecB, vecC, vecD, vecE, vecF);
또는 (중괄호로 묶인 이니셜 라이저 목록 사용) :
template<typename Func, typename T>
void foreach(Func callback, std::initializer_list<std::vector<T>> list) {
for (auto &vec : list) {
std::for_each(vec.begin(), vec.end(), callback);
}
}
foreach([](const int &i){
// do something here
}, {vecA, vecB, vecC, vecD, vecE, vecF});
또는 다음과 같이 벡터를 결합 할 수 있습니다. 두 벡터를 결합하는 가장 좋은 방법은 무엇입니까? 그런 다음 큰 벡터를 반복합니다.
'IT' 카테고리의 다른 글
Android 아이콘 대 로고 (0) | 2020.08.28 |
---|---|
pandoc을 사용하여 마크 다운에서 그림을 참조해야합니까? (0) | 2020.08.28 |
log4j2와 함께 slf4j를 사용할 가치가 있습니까? (0) | 2020.08.28 |
JSON에서 HTTP 415 지원되지 않는 미디어 유형 오류 (0) | 2020.08.28 |
Windows SDK 7.1 설치 실패 (0) | 2020.08.28 |