C++ cartesian product of multiple strings

我与影子孤独终老i 提交于 2020-01-17 01:38:08

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!