【问题标题】:Convert list of integers (IEnumerable<int>) to list of tuples (IEnumerable<IEnumerable<int>>) of specific length将整数列表 (IEnumerable<int>) 转换为特定长度的元组列表 (IEnumerable<IEnumerable<int>>)
【发布时间】:2020-04-14 15:06:24
【问题描述】:

我尝试解决下一个练习:

输入:带有count &gt;= 1;的整数列表@一些正整数k

输出: 所有可能的这个整数的元组,长度k

例如

输入: {1, 2}; k = 4

输出:

{
 {1, 1, 1, 1},
 {1, 1, 1, 2},
 {1, 1, 2, 1},
 {1, 1, 2, 2},
 {1, 2, 1, 1},
 {1, 2, 1, 2},
 {1, 2, 2, 1},
 {1, 2, 2, 2},
 {2, 1, 1, 1},
 {2, 1, 1, 2},
 {2, 1, 2, 1},
 {2, 1, 2, 2},
 {2, 2, 1, 1},
 {2, 2, 1, 2},
 {2, 2, 2, 1},
 {2, 2, 2, 2}
}

我尝试创建一个包含k 输入列表副本数组,而不是使用Combinations

public static IEnumerable<IEnumerable<T>> Combinations<T>(
  this IEnumerable<T> elements, 
  int k)
{
    return k == 0 
        ? new[] { new T[0] } 
        : elements.SelectMany((e, i) => elements
              .Skip(i + 1)
              .Combinations(k - 1)
              .Select(c => (new[] { e }).Concat(c)));
}

但是k &gt; 9 需要太长。有没有一种算法可以在短时间内解决这个问题?

【问题讨论】:

  • 您将拥有Math.Power(elements.Count(), k) 项;在你的情况下2**9 == 512 仅限项目

标签: c# algorithm statistics


【解决方案1】:

让我们摆脱递归并拥有512项目:

代码:

//TODO: you may want to declare it as IEnumerable<T[]> Combinations<T> 
public static IEnumerable<IEnumerable<T>> Combinations<T>(
  this IEnumerable<T> elements, int k) {

  if (null == elements)
    throw new ArgumentNullException(nameof(elements));
  else if (k < 0)
    throw new ArgumentOutOfRangeException(nameof(k));

  T[] alphabet = elements.ToArray();

  // Special cases
  if (alphabet.Length <= 0)
    yield break;
  else if (k == 0)
    yield break;

  int[] indexes = new int[k];

  do {
    yield return indexes
      .Select(i => alphabet[i])
      .ToArray();

    for (int i = indexes.Length - 1; i >= 0; --i)
      if (indexes[i] >= alphabet.Length - 1)
        indexes[i] = 0;
      else {
        indexes[i] += 1;

        break;
      }
  }
  while (!indexes.All(index => index == 0));
}

演示:

string report = string.Join(Environment.NewLine, Combinations(new int[] { 1, 2}, 9)
  .Select(line => string.Join(", ", line)));

Console.Write(report);

结果:512 记录)

1, 1, 1, 1, 1, 1, 1, 1, 1
1, 1, 1, 1, 1, 1, 1, 1, 2
1, 1, 1, 1, 1, 1, 1, 2, 1
1, 1, 1, 1, 1, 1, 1, 2, 2
1, 1, 1, 1, 1, 1, 2, 1, 1
1, 1, 1, 1, 1, 1, 2, 1, 2
1, 1, 1, 1, 1, 1, 2, 2, 1
1, 1, 1, 1, 1, 1, 2, 2, 2
1, 1, 1, 1, 1, 2, 1, 1, 1
...
2, 2, 2, 2, 2, 2, 1, 2, 1
2, 2, 2, 2, 2, 2, 1, 2, 2
2, 2, 2, 2, 2, 2, 2, 1, 1
2, 2, 2, 2, 2, 2, 2, 1, 2
2, 2, 2, 2, 2, 2, 2, 2, 1
2, 2, 2, 2, 2, 2, 2, 2, 2

让我们生成所有 2**20 == 1048576 项目 (k = 20),即超过 100 万 个大小为 20 的数组:

  Stopwatch sw = new Stopwatch();

  sw.Start();  

  int count = Combinations(new int[] { 1, 2 }, 20).Count();

  sw.Stop();

  Console.Write($"{count.ToString()} items at {sw.ElapsedMilliseconds:f0} milliseconds");

结果:

  1048576 items at 469 milliseconds

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-12-07
    • 1970-01-01
    • 1970-01-01
    • 2018-04-15
    • 1970-01-01
    • 2013-12-21
    相关资源
    最近更新 更多