问题
I have strings stored in a vector as such: vector<string> ex = {"ab", "cd", "ef"}
.
Now I need to create the cartesian product of these strings (number of strings in the vector, nor the length of the strings is fixed!). The result should be:
ace
acf
ade
adf
bce
bcf
bde
bdf
Is there a build-in function that exists already for this, or do you have any advice how to perform the implementation?
The single letters of the strings should be used for the cartesian product not the entire string!
回答1:
I can offer this way using the library https://cpplinq.codeplex.com/
#include <iostream>
#include <vector>
# include <algorithm>
# include <iterator>
# include <string>
# include <tuple>
# include <functional>
# include <cmath>
#include "cpplinq.hpp"
using namespace cpplinq;
std::vector<std::string> simpleTransform(const std::vector<std::string> &ex);
int main()
{
std::vector<std::string> ex1(3);
ex1[0]="ab";
ex1[1]="cd";
ex1[2]="ef";
auto VS = simpleTransform(ex1);
std::copy(VS.begin(),VS.end(),std::ostream_iterator<std::string>(std::cout,"\n"));
return 0;
}
std::vector<std::string> simpleTransform(const std::vector<std::string> &ex)
{
size_t N = ex.size();
size_t M = ex[0].size();
std::vector<std::string> VS(pow(M,N));
size_t count=0;
std::function<void(size_t,std::vector<size_t>)> Var=
[&](size_t ind,std::vector<size_t> vec)
{
if(ind==0)
{
std::string r;
r.resize(N);
for(size_t j=0;j<N;j++)
r[j] = ex[j][vec[j]-1];
VS[count] =r;
count++;
return;
}
else
{
std::vector<size_t> newvec(vec);
auto temp = N-ind+1;
newvec.resize(temp);
range(1,M)>>for_each([&](int const & j){
newvec[temp-1]=j;
Var(ind-1,newvec);});
}
};
Var(N,std::vector<size_t>());
return VS;
}
I didn't do validation of input data.
回答2:
Ok I came up with a solution. It might not be the best one and there are for sure some improvements of the code possible but its enough for my purposes and in case someone needs it too:
vector<string> getProducts(vector<string> s) {
int combinations = 1;
vector<string> res;
for (unsigned int i=0; i<s.size(); i++) {
combinations *= s.at(i).length();
}
for (unsigned int i=0; i<s.size(); i++) {
string cur = s.at(i);
int div = combinations / cur.length();
int count = 0;
for (unsigned int ch=0; ch<cur.length(); ch++) {
for (int len=0; len<div; len++) {
if (i==0) {
res.push_back(string(cur.substr(ch, 1)));
} else {
string tmp = res.at(count);
tmp.append(string(cur.substr(ch,1)));
res.at(count) = tmp;
}
count++;
}
if ((ch == cur.length()-1) && (count <= res.size()-1) && i>0) {
ch = -1;
}
}
combinations = div;
}
return res;
}
回答3:
May be the result is achievable with std::accumulate.
One needs a Binary operation of this form
std::vector<string> product(const std::vector<string> &init, string value)
{
std::string result ;
for (auto ch : value)
if (init.empty())
result.push_back(string(1, ch)) ;
else
for (auto str : init)
result.push_back(str + string(1, ch)) ;
return result ;
}
then call std::accumulate(vect.begin(), vect.end(), std::vector(), product)
来源:https://stackoverflow.com/questions/30467698/c-cartesian-product-of-multiple-strings