我有一个size = N的向量,其中每个元素的值可以从0到possible_values [i] -1。我想做一个函数,让我遍历所有这些值。
我能够使用递归生成器在Python中执行此操作:
def all_values(size,values,pos=0):
if pos == size:
yield []
else:
for v in xrange(values[pos]):
for v2 in all_values(size,values,pos+1):
v2.insert(0,v)
yield v2
possible_values=[3,2,2]
for v in all_values(3,possible_values):
print v
示例输出:
[0, 0, 0]
[0, 0, 1]
[0, 1, 0]
[0, 1, 1]
[1, 0, 0]
[1, 0, 1]
[1, 1, 0]
[1, 1, 1]
[2, 0, 0]
[2, 0, 1]
[2, 1, 0]
[2, 1, 1]
由于C ++没有Python的产量,我不知道在C ++中实现它的正确方法是什么。
可选问题: 有没有更好的方法在Python中实现它?
答案 0 :(得分:2)
这个问题让我想起了一些奇怪的混合模数算术。
我已经在Python中整理了一些东西。您应该能够在C ++中轻松地重新实现它。我有时使用输入流操作符operator>>(...)
来实现类似C ++中的生成器(懒惰评估是Python生成器的一个非常好的特性)。否则,它只是一个存储状态的对象,让您在需要时获得下一个值。
以下是一些示例代码:
class Digit:
def __init__(self, modulus):
self.modulus = modulus
self.value = 0
def __str__(self):
return str(self.value)
def __nonzero__(self):
return bool(self.value)
def increment(self):
self.value += 1
self.value %= self.modulus
return self.value == 0
class Number:
def __init__(self, moduli):
self.digits = [Digit(m) for m in moduli]
def __str__(self):
return "".join(str(d) for d in self.digits)
def __nonzero__(self):
return any(d for d in self.digits)
def increment(self):
carryover = True
for d in reversed(self.digits):
if carryover:
carryover = d.increment()
n = Number([3,2,2])
while True:
print n
n.increment()
if not n:
break
这是输出:
000
001
010
011
100
101
110
111
200
201
210
211
一些链接供进一步参考:
我在C ++中设置了一个示例:
#include <sstream>
#include <string>
#include <iostream>
#include <vector>
struct number {
struct digit {
int value;
int modulus;
digit(int modulus) : value(0), modulus(modulus) {}
bool increment() {
value = (value+1)%modulus;
return !value;
}
operator void*() {
return value ? this : 0;
}
std::string to_str() {
return std::to_string(value);
}
};
std::vector<digit> digits;
number(std::vector<int> const & moduli) {
for (auto i : moduli)
digits.push_back(digit(i));
}
void increment() {
bool carry = true;
for (auto d = digits.rbegin(); d != digits.rend(); d++)
if (carry)
carry = d->increment();
}
operator void*() {
for (digit & d : digits)
if (d) return this;
return 0;
}
std::string to_str() {
std::stringstream o;
for (auto & d : digits)
o << d.to_str();
return o.str();
}
};
int main() {
number n({3,2,2});
for(;;) {
std::cout << n.to_str() << '\n';
n.increment();
if (!n) break;
}
}
示例输出:
$ g++ test.cc -std=c++11 && ./a.out
000
001
010
011
100
101
110
111
200
201
210
211
答案 1 :(得分:1)
编辑:更简洁的一般代码,更好的评论和解释(我希望;))。
对于具有任意最大可能值的任意数量的位置,这是 迭代 ,而不是递归方法。这个想法如下。
我们在每个位置获得最大可能值。对于每个位置,我们生成一个包含该位置的所有可能值的数组。我们找到了如何挑选这些值以填充位置的组合总数(&#34;排列数&#34; ,等于所有可能值的乘积)。然后,我们遍历所有组合,将每个当前组合存储在组合数组中,并更新当前索引以在下一次迭代中选择下一个组合。我们不需要担心边界检查,因为我们固有地受到组合数量的限制。在遍历所有组合之后,我们返回一个包含所有组合的2D数组(然后打印它们)。
希望它可能有用(code on ideone.com):
#include <vector>
#include <iostream>
#include <algorithm>
namespace so {
using size = std::size_t;
using array_1d = std::vector<size>;
using array_2d = std::vector<array_1d>;
array_2d generate_combinations_all(array_1d const & _values_max) {
array_2d values_all_; // arrays of all possible values for each position
size count_combination_{1}; // number of possible combinations
for (auto i_ : _values_max) { // generate & fill in 'values_all_'
array_1d values_current_(i_);
size value_current_{0};
std::generate(values_current_.begin(), values_current_.end(), [&] {return (value_current_++);});
values_all_.push_back(std::move(values_current_));
count_combination_ *= i_;
}
array_2d combinations_all_; // array of arrays of all possible combinations
array_1d indices_(_values_max.size(), 0); // array of current indices
for (size i_{0}; i_ < count_combination_; ++i_) {
array_1d combinantion_current_; // current combination
for (size j_{0}; j_ < indices_.size(); ++j_) // fill in current combination
combinantion_current_.push_back(values_all_[j_][indices_[j_]]);
combinations_all_.push_back(std::move(combinantion_current_)); // append to 'combinations_all_'
for (size m_{indices_.size()}; m_-- > 0;) // update current indices
if (indices_[m_] < _values_max[m_] - 1) { // ++index at highest position possible
++indices_[m_];
break;
}
else indices_[m_] = 0; // reset index if it's alrady at max value
}
return (combinations_all_);
}
void print_combinations_all(array_2d const & _combinations_all) {
for (auto const & i_ : _combinations_all) { // "fancy" printing
std::cout << "[";
for (size j_{0}; j_ < i_.size(); ++j_)
std::cout << i_[j_] << ((j_ < i_.size() - 1) ? ", " : "]\n");
}
}
} // namespace so
int main() {
so::array_1d values_max_a_{3, 2, 2};
so::array_1d values_max_b_{2, 1, 3, 2};
so::print_combinations_all(so::generate_combinations_all(values_max_a_));
std::cout << "***************" << std::endl;
so::print_combinations_all(so::generate_combinations_all(values_max_b_));
return (0);
}
节目的输出:
[0, 0, 0]
[0, 0, 1]
[0, 1, 0]
[0, 1, 1]
[1, 0, 0]
[1, 0, 1]
[1, 1, 0]
[1, 1, 1]
[2, 0, 0]
[2, 0, 1]
[2, 1, 0]
[2, 1, 1]
***************
[0, 0, 0, 0]
[0, 0, 0, 1]
[0, 0, 1, 0]
[0, 0, 1, 1]
[0, 0, 2, 0]
[0, 0, 2, 1]
[1, 0, 0, 0]
[1, 0, 0, 1]
[1, 0, 1, 0]
[1, 0, 1, 1]
[1, 0, 2, 0]
[1, 0, 2, 1]
答案 2 :(得分:1)
C ++中的生成器并非易事,但仍有可能带有一些黑魔法:
http://www.codeproject.com/Articles/29524/Generators-in-C
您可以查看Safe cross platform coroutines的答案,因为尝试实际模拟python“yield”(包括PEP 342)将会带您进行一些协程实现。
如果要以C ++方式解决问题,使用对象存储“非生成器”方法的状态更为常见。
答案 3 :(得分:1)
又一个:
#include <vector>
#include <iostream>
typedef std::vector<unsigned int> uint_vector;
typedef std::vector<uint_vector> values_vector;
values_vector all_values (const uint_vector & ranges, unsigned int pos=0) {
values_vector result;
if (pos == ranges.size()) {
result.push_back (uint_vector());
}
else {
values_vector rem_result = all_values (ranges, pos+1);
for (unsigned int v = 0; v < ranges[pos]; ++v) {
for (auto it : rem_result) {
result.push_back (uint_vector(1,v));
result.back().insert (result.back().end(), it.begin(), it.end());
}
}
}
return result;
}
void print_values (const values_vector & combos) {
for (auto combo : combos) {
std::cout << "[ ";
for (auto num : combo) {
std::cout << num << ' ';
}
std::cout << "]\n";
}
}
int main () {
uint_vector ranges {3,2,2};
print_values (all_values (ranges));
return 0;
}
答案 4 :(得分:0)
另一种实施方式。
PS:可以自定义值的打印,使其看起来像Python的输出,但我认为没有必要说明生成输出数据的算法。
#include <iostream>
#include <vector>
using namespace std;
void print_values(vector<vector<int> > const& values)
{
for ( auto v1 : values)
{
for ( auto v : v1 )
{
cout << v << " ";
}
cout << "\n";
}
}
vector<vector<int> > get_all_values(int size,
vector<int>::const_iterator iter)
{
vector<vector<int> > ret;
if ( size == 1 )
{
for (int v = 0; v != *iter; ++v )
{
std::vector<int> a = {v};
ret.push_back(a);
}
return ret;
}
vector<vector<int> > prev = get_all_values(size-1, iter+1);
for (int v = 0; v != *iter; ++v )
{
for ( vector<int>& v1 : prev )
{
std::vector<int> a = {v};
a.insert(a.end(), v1.begin(), v1.end());
ret.push_back(a);
}
}
return ret;
}
vector<vector<int> > get_all_values(vector<int> const& in)
{
return get_all_values(in.size(), in.begin());
}
int main()
{
vector<int> a{2};
vector<int> b{2,3};
vector<int> c{2,3,2};
cout << "----------\n";
print_values(get_all_values(a));
cout << "----------\n";
print_values(get_all_values(b));
cout << "----------\n";
print_values(get_all_values(c));
cout << "----------\n";
return 0;
}
运行程序生成的输出:
----------
0
1
----------
0 0
0 1
0 2
1 0
1 1
1 2
----------
0 0 0
0 0 1
0 1 0
0 1 1
0 2 0
0 2 1
1 0 0
1 0 1
1 1 0
1 1 1
1 2 0
1 2 1
----------