动态组合算法

发布于 2024-08-28 21:27:18 字数 1686 浏览 10 评论 0 原文

我的代码有一个名为 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)
      }
}

但我需要找到一种方法来构建列表iCOMBINATIONS 用于任何给定数量的输入及其事件。有什么想法吗?

实际上还有比这更好的算法吗? 任何可以帮助我的伪代码都会很棒。

C#(或 VB)

谢谢

My code has a list called INPUTS, that contains a dynamic number of lists, let's call them A, B, C, .. N. These lists contain a dynamic number of Events

I would like to call a function with each combination of Events. To illustrate with an example:

INPUTS: A(0,1,2), B(0,1), C(0,1,2,3)

I need to call my function this many times for each combination (the input count is dynamic, in this example it is three parameter, but it can be more or less)

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])

This is what I have thought of so far:
My approach so far is to build a list of combinations. The element combination is itself a list of "index" to the input arrays A, B and C. For our example:

my list iCOMBINATIONS contains the following iCOMBO lists

(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)

Then I would do this:

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)
      }
}

But I need to find a way to build the list iCOMBINATIONS for any given number of INPUTS and their events. Any ideas?

Is there actually a better algorithm than this?
any pseudo code to help me with will be great.

C# (or VB)

Thank You

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

海螺姑娘 2024-09-04 21:27:18

您可以使用数组来保存每个列表的索引。例子:

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);

You can use an array to hold the indexes for each list. Example:

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);
权谋诡计 2024-09-04 21:27:18

这就是排列问题。您可以看一下:

http://www. Interactive-sw.co.uk/iangblog/2004/09/16/permuterate

This is permutation problem. You may take a look at this:

http://www.interact-sw.co.uk/iangblog/2004/09/16/permuterate

时光无声 2024-09-04 21:27:18

我前段时间遇到了类似的问题(生成组合),我使用了以下代码: http://www .merriampark.com/comb.htm。它是java,但我把它翻译成C#没有任何问题。

I had similar problem some time ago (generating combinations), I've used code from: http://www.merriampark.com/comb.htm . It's java, but I hadn't any problems to translate it into C#.

往事随风而去 2024-09-04 21:27:18

将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)

Put A,B,C in matrix!
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)
世界如花海般美丽 2024-09-04 21:27:18

看来您真正想要的,本身既不是排列,也不是组合。您想要查看笛卡尔积(请参阅此处)的多个集合,其迭代可能涉及迭代各个集合的组合。

然而,这与组合问题不同,因为您正在寻找从每个集合中选择 1 个元素的方法。执行此操作的方法数量就是集合的大小。组合问题通常涉及选择k - 从一组n中选择许多东西 - 许多东西,其中k=1或n 是微不足道的。

此处。 (包括乔恩·斯基特的一首)。

如果您使用 .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);
    }
}

It would seem that what you really want, is neither a permutation, nor a combination, per se. You want to look at the cartesian product (see here) of several sets, the iteration over which may involve iterating through combinations of individual sets.

However, this is unlike a combination problem, because you are looking for the ways to choose 1 element from each set. The number of ways to do this is the size of the set. Combinations problems usually involve choose k-many things from a set of n-many things, where k=1 or n is trivial.

Several methods of producing iterators in C# have been discussed here. (Including one by Jon Skeet).

If you are using .NET, you may also be interested in developed combinatorics modules, such as KwCombinatorics at CodePlex.

edit Now, with LINQ to the rescue:

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);
    }
}
简单爱 2024-09-04 21:27:18

@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>(具有可能的值)。输出与原始答案相同。性能更好。

A modified version of @Guffa's answer. I am by no means a creator of this code.

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);

Instead of using List<List<int>> - with possible values - use List<int> describing the amount of elements in collection. The output is the same an in original answer. The performance is better.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文