按每个顺序测试每个函数组合

Test every combination of functions in every order

本文关键字:组合 函数 顺序 测试      更新时间:2023-10-16

我有一堆函数,a.processb.processc.process...,我们称它们为abc...都以std::string为参数并返回std::string.

给定一个初始std::string s,我想生成abc组合的所有可能输出。以任何顺序调用并给出s作为初始输入。

例如,我想计算a(s)b(s)c(s)a(b(s))a(c(s))b(a(s))b(c(s))c(a(s))c(b(s))a(b(c(s)))等。

我想我可以做一个函数来生成列表的每个排列,类似于 Python 的itertools.permutations,但我这里有两个主要问题:

  • 不仅想要每一个排列,我想要每个顺序的每一个排列。

  • 更重要的是,我不知道如何将函数存储在数组中,就像在 Python 中一样

此外,我需要每个可能的输出都带有生成它的函数组合,因此对于我上面给出的示例,我知道输出按以下顺序排列:"a""b""c""ab""ac""ba""bc""ca""cb""abc"等。

我如何在C++中实现它?

要在数组中存储函数,需要使用函数指针。像这样的事情就可以了:

typedef string (*t_fnPtr)(string);
t_fnPtr fnPtrArray[10]; //Initialize this with your functions

然后,只需生成数组的所有组合并将其应用于字符串即可。看看这个问题。

我只是将 Sid 的答案充实到实际代码中。与Galik的答案不同,这不会产生重复

#include<iostream>
#include<string>
#include<vector>
#include<algorithm>
using Fn = std::string (*)(std::string);
std::string apply_all(const std::vector<Fn>& fns, std::string s)
{
for(auto fn : fns)
s = fn(s);
return s;
}
int main()
{
std::string s = /* some string */;
std::vector<Fn> functions{/* initialize with functions */};
int n = functions.size();
for(int r = 1; r <= n; r++)
{
std::vector<bool> v(n);
std::fill(v.begin(), v.begin() + r, true);  // select r functions
// permute through all possible selections of r functions
do {
std::vector<Fn> selected;
for(int i = 0; i < n; ++i)
if(v[i])
selected.push_back(functions[i]);
std::sort(selected.begin(), selected.end());
// permute through the r functions
do {
std::cout << apply_all(selected, s) << std::endl;
} while(std::next_permutation(selected.begin(), selected.end()));
} while(std::prev_permutation(v.begin(), v.end()));
}
}

现场示例

一些想法和伪代码

函数指针数组,每个函数一个。

typedef std::string (*Func)(std::string const&);
Func const func_array[] = {&a, &b, &c};
int const n = sizeof array / sizeof array[0];  // number of functions

我们需要

n choose 1 to get 1-element combinations a, b, c
n choose 2 to get 2-element combinations ab, ac, bc
n choose 3 to get 3-element combinations abc

此外,对于每个组合,我们需要所有可能的排列。

For all k = 1 to n, 
All permutations of (All combinations of n-choose-k) 

素描

for i = 0 to 2^(n-1):
xi = elements of func_array corresponding to the '1' bits in i
used std::next_permutation() to generate all permutations of xi

查看 https://en.wikipedia.org/wiki/Power_set 和 http://en.cppreference.com/w/cpp/algorithm/next_permutation

如果我理解正确了这个问题,也许是这样的。它使用std::next_permutation遍历进程的每个顺序,对于每个排序,它选择要(连续)对输入进行操作的每个子列表或进程:

std::string process_1(std::string const& s)
{ return s + 'a'; }
std::string process_2(std::string const& s)
{ return s + 'b'; }
std::string process_3(std::string const& s)
{ return s + 'c'; }
int main(int, char** argv)
{
using process = std::string(*)(std::string const&);

std::vector<process> processes;
processes.push_back(process_1);
processes.push_back(process_2);
processes.push_back(process_3);
std::vector<std::string> outputs;
std::sort(std::begin(processes), std::end(processes));
do
{
for(auto p = std::begin(processes); p != std::end(processes); ++p)
{
std::string s = "";
for(auto p1 = p; p1 != std::end(processes); ++p1)
s = (*p1)(s);
outputs.push_back(s);
}
}
while(std::next_permutation(std::begin(processes), std::end(processes)));
for(auto const& o: outputs)
std::cout << o << 'n';
}

输出:

abc
bc
c
acb
cb
b
bac
ac
c
bca
ca
a
cab
ab
b
cba
ba
a

注意:此方法似乎会产生一些重复项。应该有一种聪明的数学方法来消除它们,现在我无法消除它们,但您可以随时保持std::set<std::vector<process>>来记录已经尝试过的每个组合,以确保没有重复。或者只是从输出中删除重复项。