我的代码有一个名为INPUTS的列表,其中包含动态数量的列表,我们称之为A,B,C,.. N.这些列表包含动态数量的事件
我想用每个事件组合调用一个函数。举例说明:
INPUTS: A(0,1,2), B(0,1), C(0,1,2,3)
我需要为每个组合多次调用我的函数(输入计数是动态的,在这个例子中它是三个参数,但它可以或多或少)
function(A[0],B[0],C[0])
function(A[0],B[1],C[0])
function(A[0],B[0],C[1])
function(A[0],B[1],C[1])
function(A[0],B[0],C[2])
function(A[0],B[1],C[2])
function(A[0],B[0],C[3])
function(A[0],B[1],C[3])
function(A[1],B[0],C[0])
function(A[1],B[1],C[0])
function(A[1],B[0],C[1])
function(A[1],B[1],C[1])
function(A[1],B[0],C[2])
function(A[1],B[1],C[2])
function(A[1],B[0],C[3])
function(A[1],B[1],C[3])
function(A[2],B[0],C[0])
function(A[2],B[1],C[0])
function(A[2],B[0],C[1])
function(A[2],B[1],C[1])
function(A[2],B[0],C[2])
function(A[2],B[1],C[2])
function(A[2],B[0],C[3])
function(A[2],B[1],C[3])
这是我到目前为止所想到的: 到目前为止,我的方法是建立一个组合列表。元素组合本身是输入数组A,B和C的“索引”列表。对于我们的示例:
我的列表iCOMBINATIONS包含以下iCOMBO列表
(0,0,0)
(0,1,0)
(0,0,1)
(0,1,1)
(0,0,2)
(0,1,2)
(0,0,3)
(0,1,3)
(1,0,0)
(1,1,0)
(1,0,1)
(1,1,1)
(1,0,2)
(1,1,2)
(1,0,3)
(1,1,3)
(2,0,0)
(2,1,0)
(2,0,1)
(2,1,1)
(2,0,2)
(2,1,2)
(2,0,3)
(2,1,3)
然后我会这样做:
foreach( iCOMBO in iCOMBINATIONS)
{
foreach ( P in INPUTS )
{
COMBO.Clear()
foreach ( i in iCOMBO )
{
COMBO.Add( P[ iCOMBO[i] ] )
}
function( COMBO ) --- (instead of passing the events separately)
}
}
但我需要找到一种方法来为任何给定数量的INPUTS及其事件构建列表iCOMBINATIONS。有什么想法吗?
实际上有比这更好的算法吗? 任何帮助我的伪代码都会很棒。
C#(或VB)
谢谢
答案 0 :(得分:1)
您可以使用数组来保存每个列表的索引。例如:
List<List<int>> lists = new List<List<int>> {
new List<int> { 0,1,2 },
new List<int> { 0,1 },
new List<int> { 0,1,2,3 }
};
int[] cnt = new int[lists.Count];
int index;
do {
Console.WriteLine(String.Join(",", cnt.Select((c,i) => lists[i][c].ToString()).ToArray()));
index = cnt.Length - 1;
do {
cnt[index] = (cnt[index] + 1) % lists[index].Count;
} while(cnt[index--] == 0 && index != -1);
} while (index != -1 || cnt[0] != 0);
答案 1 :(得分:0)
这是排列问题。你可以看看这个:
http://www.interact-sw.co.uk/iangblog/2004/09/16/permuterate
答案 2 :(得分:0)
前段时间我遇到类似的问题(生成组合),我使用的代码来自:http://www.merriampark.com/comb.htm。这是java,但我把它转换成C#没有任何问题。
答案 3 :(得分:0)
把A,B,C放在矩阵中! M = [A,B,C]
recursive_caller(d,params):
if d == len(M):
function(params)
return
for i in M[d]:
params[d]=i
recursive_caller(d+1,params)
答案 4 :(得分:0)
看起来你真正想要的东西,本身既不是排列,也不是组合。您想要查看几个集合的cartesian product(请参阅here),其迭代可能涉及迭代各个集合的组合。
但是,这与组合问题不同,因为您正在寻找从每个集合中选择1个元素的方法。执行此操作的方法的数量是集合的大小。组合问题通常涉及从一组 n - 很多东西中选择 k - 很多东西,其中 k = 1或 n 很简单。
已经讨论了几种在C#中生成迭代器的方法here。 (包括Jon Skeet的一个)。
如果您使用的是.NET,您可能也对开发的组合模块感兴趣,例如CodePlex上的KwCombinatorics。
编辑现在,借助LINQ救援:
private void cartesian1()
{
textAppend("Cartesian 1");
var setA = new[] { "whole wheat", "white", "rye" };
var setB = new[] { "cold cut", "veggie", "turkey", "roast beef" };
var setC = new[] { "everything", "just mayo" };
var query =
from bread in setA
from meat in setB
from toppings in setC
let sandwich = String.Format("{1} on {0} with {2}",
bread, meat, toppings)
select sandwich;
foreach( string sandwich in query )
{
textAppend(sandwich);
}
}
答案 5 :(得分:0)
@ Guffa答案的修改版本。我绝不是这段代码的创造者。
List<int> lists = new List<int> { 3, 2, 4 };
int[] cnt = new int[lists.Count];
int index;
do
{
Console.WriteLine(String.Join(",", cnt));
index = cnt.Length - 1;
do
{
cnt[index] = (cnt[index] + 1) % lists[index];
} while (cnt[index--] == 0 && index != -1);
} while (index != -1 || cnt[0] != 0);
不使用List<List<int>>
- 使用可能的值 - 使用List<int>
来描述集合中的元素数量。输出与原始答案中的输出相同。表现更好。