1

Python の itertools.combinations(input, 2) と同じことを行うために C++11 関数で遊んでいますが、これまでのところ、これは私が持っているものです:

@DavidRodríguez-dribeasによって提案されたように、EDITは外側のラムダを削除しました

#include <iostream>
#include <functional>
#include <vector>

using namespace std;

template <class T>
function<pair<T*, T*>()> combinations(vector<T> & input) {
  auto it1 = input.begin();
  auto end = input.end();
  auto it2 = next(it1);
  return [=]() mutable {
      if (it2 == end) {
        it1++;
        it2 = next(it1);
      }   
      if (it2 != end)
        return pair<T*,T*>(&(*it1), &(*it2++));
      return pair<T*,T*>(&*end, &*end);
    };  
};

int main (void) {
  vector<int> numbers{1,2,3,4,5,6};
  auto func = combinations(numbers);
  while ( true ) { 
    auto i = func();
    if (i.first == &*(numbers.end())) break;
    cout << *(i.first) << ',' << *(i.second) << endl;
  }

  return 0;
};

組み合わせを反復するために使用される方法に満足していません。それをクリーンアップするためのアドバイスはありますか?

4

2 に答える 2

1

これを行うための私のお気に入りの方法に関するドキュメントとコードを次に示します。そして、これがあなたの例のためにそのライブラリがどのように使われるかです:

#include <iostream>
#include <vector>
#include "combinations"

using namespace std;

int main (void) {
  vector<int> numbers{1,2,3,4,5,6};
  for_each_combination(numbers.begin(), numbers.begin()+2, numbers.end(),
           [](vector<int>::const_iterator b, vector<int>::const_iterator e)
           {
              if (b != e)
              {
                cout << *b;
                for (auto i = b+1; i != e; ++i)
                    cout << ',' << *i;
                cout << endl;
              }
              return false;
           });
}

1,2
1,3
1,4
1,5
1,6
2,3
2,4
2,5
2,6
3,4
3,5
3,6
4,5
4,6
5,6

必要が生じた場合は、使用例を変更して、一度に2つではなく3つまたは4つの項目を考慮することは簡単です。一度にNからのさまざまな順列kを処理することもできます。

アップデート

ベクトル内での移動/交換が効率的ではなかったアイテムのベクトルをどのように処理するかを示すために、間接参照のレベルを追加します。

#include <iostream>
#include <vector>
#include "combinations"

using namespace std;

int main (void) {
  vector<int> numbers{1,2,3,4,5,6};
  vector<vector<int>::const_iterator> num_iters;
  num_iters.reserve(numbers.size());
  for (auto i = numbers.begin(); i != numbers.end(); ++i)
    num_iters.push_back(i);
  for_each_combination(num_iters.begin(), num_iters.begin()+2, num_iters.end(),
           [](vector<vector<int>::const_iterator>::const_iterator b,
              vector<vector<int>::const_iterator>::const_iterator e)
           {
              if (b != e)
              {
                cout << **b;
                for (auto i = b+1; i != e; ++i)
                    cout << ',' << **i;
                cout << endl;
              }
              return false;
           });
}
于 2012-11-27T21:43:50.917 に答える
1

Oliver Kowalke のコルーチン ライブラリが Boosts のピア レビューで承認されており、次のバージョンに含まれることを期待しています。銃を少し飛ばして、boost-dev リポジトリ (https://gitorious.org/boost-dev/boost-dev) のコルーチン ブランチを使用して試してみました。

g++ -I path/to/boost-dev -std=c++11 test_code.cpp -o run_test_code -static -L path/to/boost-dev/stage/lib/ -lboost_context

#include <boost/coroutine/all.hpp>
#include <boost/bind.hpp>
#include <boost/range.hpp>
#include <iostream>
#include <vector>

using namespace std;
using namespace boost;

template <typename T>
using coro_pairT_void = coroutines::coroutine<pair<T&,T&>(void)>;

template <typename T>
void combinations(typename coro_pairT_void<T>::caller_type & self, vector<T> & input ) { 
  for (auto it1 = input.begin(), itend = input.end(); it1 != itend; it1++) {
    for (auto it2 = std::next(it1); it2 != itend; it2++) {
      self(pair<T&, T&>(*it1,*it2));
    }   
  }
};

int main( void ) { 
  vector<int> numbers{1,2,3,4,5,6};
  coro_pairT_void<int> func(bind(combinations<int>, _1, numbers));
  for (auto it(begin(func)), itend(end(func)); it != itend; ++it) {
    cout << it->first << ',' << it->second << endl;
  }
  return 0;
};
于 2012-11-29T23:38:53.740 に答える