C# 将一个列表拆分为 n 组的所有组合——代码迁移自 Python

标签 c# python algorithm combinations

我追求的算法有一个很好的实现 here (通过@lazy dog)。但是,我需要在 C# 中使用它,并且由于 C# 缺少 yield from 并且可能是我自己的头脑笨拙,所以转换并非微不足道。

这是我目前拥有的:

public static IEnumerable<ArrayList> sorted_k_partitions(int[] seq, int k) {
  var n = seq.Length;
  var groups = new ArrayList(); //a list of lists, currently empty

  IEnumerable<ArrayList> generate_partitions(int i) {
    if (i >= n) {
      // this line was the bug, was not creating a 
      //   deep clone of the list of lists
      // yield return new ArrayList(groups); 
      yield return new ArrayList(groups.ToArray().Select(g => ((List<int>)g).ToList())); 
      // Ugly but that is because we are using ArrayList
      // Using proper List<List<int>> cleans this up significantly
    }
    else {
      if (n - i > k - groups.Count)
        foreach (List<int> group in new ArrayList(groups)) {
          group.Add(seq[i]);
          // yield from generate_partitions(i + 1);
          foreach (var d in generate_partitions(i + 1)) {
            yield return d;
          }
          group.RemoveAt(group.Count - 1);
        }

      if (groups.Count < k) {
        groups.Add(new List<int> {seq[i]});
        foreach (var d in generate_partitions(i + 1)) {
          // things start breaking down here, as this yield return
          //  appears to release flow control and we then get the 
          //  yield return above.  I have debuged this and the python
          //  version and the python version does not do this.  Very hard
          //  to explain considering I don't fully understand it myself
          yield return d;
        }
        groups.RemoveAt(groups.Count - 1);
      }
    }
  }
  return generate_partitions(0);
  // don't worry about the sorting methods in the python 
  //   version, not needed
}

任何人都可以看到任何明显的错误吗,我敢肯定我对 Python 的 yield from 和协程缺乏理解正在伤害我。

编辑:发现错误,在上面添加评论

最佳答案

好的,我想出了一个很好的解决方案:

public static IEnumerable<List<List<int>>> CreatePartitions(int[] seq, int k) {
  var n = seq.Length;
  var groups = new List<List<int>>(); 

  IEnumerable<List<List<int>>> generate_partitions(int i) {
    if (i >= n) {
      yield return new List<List<int>>(groups.Select(g => g.ToList()));
    }
    else {
      if (n - i > k - groups.Count)
        foreach (var group in new List<List<int>>(groups)) {
          group.Add(seq[i]);
          foreach (var d in generate_partitions(i + 1)) {
            yield return d;
          }
          group.RemoveAt(group.Count - 1);
        }

      if (groups.Count < k) {
        groups.Add(new List<int> {seq[i]});
        foreach (var d in generate_partitions(i + 1)) {
          yield return d;
        }
        groups.RemoveAt(groups.Count - 1);
      }
    }
  }
  return generate_partitions(0);
}

这比 python 快一点,但仍然不是很好。我尝试了并行化,但没有走得太远。我还通过尝试删除一些对象创建并改用 Array.Copy 进行了实验。造成的困惑不值得微不足道的性能改进。我猜这只是很慢,因为随着数字变大(比如 15-20 项的序列),组合的数量会非常庞大​​,没有任何优化可以帮助使它成为一个更容易处理的问题。

关于C# 将一个列表拆分为 n 组的所有组合——代码迁移自 Python,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46419228/

相关文章:

php - 如何全天将系统中的线索平均分配给两方?

c# - C# 中的三层应用程序 - 放置数据和业务模型的位置

c# - SQL Where in to Linq with DataTable

python - 如何使用 pyOpenSSL 生成证书以使其安全连接?

python - pypdf 将多个pdf文件合并为一个pdf

c++ - 在 C++ 中,检查一个数字是否已经添加到列表中,而不用暴力搜索该列表

ruby - 了解 Ruby 示例中的按位或 '|'

c# - 如何以编程方式滚动 ListView 项目

c# - 如何确定 Expression<Func<T, object>> 是否对 EntityFramework .Include 有效

python - 当 QListview 项的复选框更改时发出信号