【问题标题】:Just in time computation of combinations [duplicate]及时计算组合[重复]
【发布时间】:2016-03-31 04:46:20
【问题描述】:

我想对 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"}

【问题讨论】:

  • 最简单的解决方案是计算它,但您当前正在计算它,但使用收益回报。
  • 我不明白你是如何计算你的组合的。您有“FT”和“TF”,但有“UT”而没有“TU”。

标签: c# algorithm combinations


【解决方案1】:

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

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

【讨论】:

    【解决方案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;
            }
        }
    }
    

    【讨论】:

      【解决方案3】:

      尚不清楚您是如何获得 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});
                  }
              }
          }
      }
      

      【讨论】:

        【解决方案4】:

        您可以通过对组合进行排序来实现这一点,因此您基本上可以在它们和从 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

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2016-10-22
          • 1970-01-01
          • 1970-01-01
          • 2021-08-31
          • 2018-11-29
          • 1970-01-01
          相关资源
          最近更新 更多