给出以下Python(来自http://norvig.com/sudoku.html)
def cross(A, B):
"Cross product of elements in A and elements in B."
return [a+b for a in A for b in B]
cols = '123456789'
rows = 'ABCDEFGHI'
squares = cross(rows, cols)
这会产生:
['A1', 'A2', 'A3', 'A4', 'A5', 'A6', 'A7', 'A8', 'A9', 'B1', 'B2', 'B3', ...]
作为练习,我想在C ++中做同样的事情。目前我有:
#include <iostream>
#include <map>
#include <vector>
using std::string;
using std::vector;
static vector<string> cross_string(const string &A, const string &B)
{
vector<string> result;
for (string::const_iterator itA = A.begin(); itA != A.end(); ++itA) {
for (string::const_iterator itB = B.begin(); itB != B.end(); ++itB) {
char s[] = {*itA, *itB, 0};
result.push_back(string(s));
}
}
return result;
}
int main(int argc, char** argv)
{
const char digits[] = "123456789";
const char rows[] = "ABCDEFGHI";
vector<string> res = cross_string(rows, digits);
for (vector<string>::const_iterator it = res.begin();
it != res.end(); ++it) {
std::cout << *it << std::endl;
}
}
这有效,但我希望有更好的方法。这也只做字符串,而python做任何列表......
<小时/> 编辑:
感谢所有回复。我接受了我最了解的那个,但Alf的答案紧随其后。我注意到所有人都使用过C ++ 11并且想知道作为C ++的新手,我应该直接采用它而不是学习旧标准。但这可能是另一个问题的最佳选择。
答案 0 :(得分:5)
只是提供代码比解释更短:
#include <iostream> // std::wcout, std::endl
#include <string> // std::string
#include <utility> // std::begin, std::end
#include <vector>
using namespace std;
string sum( char const a, char const b ) { return string() + a + b; }
template< class Container >
auto cross( Container const& a, Container const& b )
-> vector< decltype( sum( *begin( a ), *begin( b ) ) ) >
{
typedef decltype( sum( *begin( a ), *begin( b ) ) ) ResultItem;
vector< ResultItem > result;
for( auto&& itemA : a ) for( auto&& itemB : b )
{
result.push_back( sum( itemA, itemB ) );
}
return result;
}
wostream& operator<<( wostream& stream, string const& s )
{
return (stream << s.c_str());
}
template< class Item >
wostream& operator<<( wostream& stream, vector<Item> const& v )
{
stream << "[";
bool isFirstItem = true;
for( auto&& item : v )
{
if( !isFirstItem ) { stream << ", "; }
stream << item;
isFirstItem = false;
}
stream << "]";
return stream;
}
int main()
{
string const cols = "123456789";
string const rows = "ABCDEFGHI";
auto const squares = cross( cols, rows );
wcout << squares << endl;
}
答案 1 :(得分:4)
奇怪的是,C ++算法库中缺少cross_product
。它可以很容易地添加,但正如杰里和阿尔夫的答案所显示的那样,对如何做到最好的看法存在分歧。事实上,我仍然会做不同的事情。 Jerry的界面符合其他C ++算法的界面,但他并没有抽象出交叉产品操作,我这样做了:
template <typename InputIt1,
typename InputIt2,
typename OutputIt,
typename F>
void cross_product(InputIt1 begin1,
InputIt1 end1,
InputIt2 begin2,
InputIt2 end2,
OutputIt out,
F f) {
for (auto i = begin1; i != end1; ++i)
for (auto j = begin2; j != end2; ++j)
*out++ = f(*i, *j);
}
在您的示例中,调用将如下所示:
auto digits = "1234546789";
auto chars = "ABCDEFGHI";
vector<string> result;
cross_product(digits, digits + strlen(digits),
chars, chars + strlen(chars),
back_inserter(result),
[](char a, char b) { return string() + a + b; });
(难道我不喜欢C ++ 11吗?是的,我确实喜欢。)
在一个合适的库中,我提供了第二个重载,它提供了一个默认的f
操作,它创建了一个类似于Jerry代码所做的元组。甚至可以想到进一步抽象这个以允许两个以上的范围 - 毕竟,Python列表理解允许你迭代两个以上的范围。)
答案 2 :(得分:3)
你当然可以使这个通用:
template <class InIt1, class InIt2, class OutIt>
void cross_product(InIt1 b1, InIt1 e1, InIt2 b2, InIt2 e2, OutIt out) {
for (auto i=b1; i != e1; ++i)
for (auto j=b2; j != e2; ++j)
*out++ = std::make_pair(*i, *j);
}
请注意,您通常不希望模板参数是集合中对象的类型,而是集合的迭代器类型。例如,你可以这样使用:
std::ostream &operator<<(std::ostream &os, std::pair<char, int> const &d) {
return os << d.first << d.second;
}
int main() {
std::vector<char> a{'A', 'B', 'C', 'D'};
std::vector<int> b{ 1, 2, 3, 4};
cross_product(a.begin(), a.end(), b.begin(), b.end(),
infix_ostream_iterator<std::pair<char, int> >(std::cout, ", "));
return 0;
}
...应该产生这样的输出:
A1, A2, A3, A4, B1, B2, B3, B4, C1, C2, C3, C4, D1, D2, D3, D4
另请注意,我在大多数代码中都使用了一些C ++ 11功能。如果您使用的是较旧的编译器(或Microsoft的编译器),则需要进行一些编辑。
答案 3 :(得分:0)
对A类和B类进行模板化,然后进行成对std::pair<A, B>