在实现这个通用的同时归并排序 http://en.wikipedia.org/wiki/Merge_sort,作为一种代码卡塔 http://en.wikipedia.org/wiki/Kata_%28programming%29,我偶然发现了 IEnumerable 和 List 之间的区别,我需要帮助才能弄清楚。
这是归并排序
public class MergeSort<T>
{
public IEnumerable<T> Sort(IEnumerable<T> arr)
{
if (arr.Count() <= 1) return arr;
int middle = arr.Count() / 2;
var left = arr.Take(middle).ToList();
var right = arr.Skip(middle).ToList();
return Merge(Sort(left), Sort(right));
}
private static IEnumerable<T> Merge(IEnumerable<T> left, IEnumerable<T> right)
{
var arrSorted = new List<T>();
while (left.Count() > 0 && right.Count() > 0)
{
if (Comparer<T>.Default.Compare(left.First(), right.First()) < 0)
{
arrSorted.Add(left.First());
left=left.Skip(1);
}
else
{
arrSorted.Add(right.First());
right=right.Skip(1);
}
}
return arrSorted.Concat(left).Concat(right);
}
}
如果我删除.ToList()
on the left
and right
它无法正确排序的变量。你明白为什么吗?
Example
var ints = new List<int> { 5, 8, 2, 1, 7 };
var mergeSortInt = new MergeSort<int>();
var sortedInts = mergeSortInt.Sort(ints);
With .ToList()
[0]: 1
[1]: 2
[2]: 5
[3]: 7
[4]: 8
Without .ToList()
[0]: 1
[1]: 2
[2]: 5
[3]: 7
[4]: 2
Edit
正是我愚蠢的测试让我陷入了困境。
我是这样测试的:
var sortedInts = mergeSortInt.Sort(ints);
ints.Sort();
if (Enumerable.SequenceEqual(ints, sortedInts)) Console.WriteLine("ints sorts ok");
只需将第一行更改为
var sortedInts = mergeSortInt.Sort(ints).ToList();
消除了问题(以及惰性评估)。
编辑2010-12-29
我以为我会弄清楚惰性求值是如何把事情弄乱的,但我就是不明白。
去除.ToList()
在上面的 Sort 方法中像这样
var left = arr.Take(middle);
var right = arr.Skip(middle);
然后试试这个
var ints = new List<int> { 5, 8, 2 };
var mergeSortInt = new MergeSort<int>();
var sortedInts = mergeSortInt.Sort(ints);
ints.Sort();
if (Enumerable.SequenceEqual(ints, sortedInts)) Console.WriteLine("ints sorts ok");
调试的时候可以看到之前ints.Sort()
a sortedInts.ToList()
returns
[0]: 2
[1]: 5
[2]: 8
但是之后ints.Sort()
它返回
[0]: 2
[1]: 5
[2]: 5
这里究竟发生了什么?