及时计算组合

时间:2016-03-30 19:17:07

标签: c# algorithm combinations

我想对N个变量的每个三元组合做一些事情:

示例1:

T
F
U

示例2:

TT
FT
UT
TF
FF
UF
UU

有没有办法计算这个但只是根据需要:例如:

    var combinator = new Combinator<string>(2, {"T","F","U"});
    List<String> tt = combinator.Next(); 
    //tt contains {"T","T"}

4 个答案:

答案 0 :(得分:3)

您可以在迭代器方法中实现它:

private IEnumerable<List<T>> Combinations<T>(int n, T[] values)
{
    if (n == 0) yield return new List<T>();
    else
    {
        foreach (var list in Combinations(n - 1, values))
            foreach (var item in values)
            {
                var items = new List<T>(list);
                items.Add(item);
                yield return items;
            }
    }
}

这会创建所有组合,但会以懒惰的方式进行。

如果您愿意,可以像这样创建Combinator类:

class Combinator<T>
{
    IEnumerator<List<T>> enumerator;

    public Combinator(int n, T[] values)
    {
        enumerator = Combinations(n, values).GetEnumerator();
    }

    public List<T> Next()
    {
        return enumerator.MoveNext() ? enumerator.Current : null;
    }

    private IEnumerable<List<T>> Combinations<T>(int n, T[] values) { ... }
}

答案 1 :(得分:2)

可能不是计算效率最高的,但它的组合系统,所以复杂性可能不会太糟糕:

public static IEnumerable<List<T>> Combinations<T>( int count, IEnumerable<T> items )
{
    if( count <= 0 ) yield break;
    if( count == 1 ) 
    {
        foreach( var item in items ) yield return new List<T> { item };
        yield break;
    }

    foreach( var item in items )
    {
        foreach( var combo in Combinations<T>( count - 1, items ) )
        {
            var result = new List<T> { item };
            result.AddRange( combo );
            yield return result;
        }
    }
}

答案 2 :(得分:1)

目前尚不清楚如何获得TFU的组合。

您只列出以下内容:

TT
FT
UT
TF
FF
UF
UU

然而,缺少两种组合,它应该是这样的(据我所知):

TT
FT
UT
TF
FF
UF
TU
FU
UU

假设后者实际上是正确的列表,那么您可以“按需”计算它,如下所示:

using System;
using System.Collections.Generic;
using System.Linq;

namespace ConsoleApplication1
{
    class Program
    {
        public static void Main()
        {
            foreach (var combination in Combinator(new [] { "T", "F", "U" }, 2))
                Console.WriteLine(string.Concat(combination));
        }

        public static IEnumerable<IEnumerable<T>> Combinator<T>(IEnumerable<T> sequence, int count)
        {
            if (count == 0)
            {
                yield return Enumerable.Empty<T>();
                yield break;
            }

            foreach (T startingElement in sequence)
            {
                IEnumerable<T> remainingItems = sequence;

                foreach (IEnumerable<T> permutationOfRemainder in Combinator(remainingItems, count - 1))
                    yield return permutationOfRemainder.Concat(new [] { startingElement});
            }
        }
    }
}

答案 3 :(得分:0)

你可以通过给出一些排序来实现这一点,所以你基本上可以在它们之间分配一个映射,从1到n ^ m(其中n是排列的长度,m是字符串的数量)。然后保存状态。

然而,这样做是为了重新实现IEnumerable。 https://msdn.microsoft.com/de-de/library/system.collections.ienumerable(v=vs.110).aspx

更简单一点,如果你在某种foreach循环中需要它,那就是只使用一个返回IEnumerable的方法。如果使用yield语法,IEnumerable将被延迟评估。 http://www.dotnetperls.com/yield