我在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
和协同程序缺乏了解在这里伤害了我。
编辑:发现错误,在上面添加评论
答案 0 :(得分:1)
好的,我提出的一个好的工作解决方案就在这里:
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项的seq),组合的数量是巨大的,没有任何优化可以帮助将其变成一个更容易处理的问题。
答案 1 :(得分:0)
你到这里有什么行为?
在我看来yield return generate_partitions(i + 1);
而不是foreach循环应该可以正常工作。它将使用新值i+1