List 和 IEnumerable 的区别

2024-01-22

在实现这个通用的同时归并排序 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

这里究竟发生了什么?


你的功能是正确的 - 如果你检查结果Merge,你会看到结果已排序(例子) http://ideone.com/NirvK.
那么问题出在哪里呢?正如您所怀疑的那样,您的测试是错误的 -你打电话时Sort在您的原始列表中,您可以更改从中派生的所有集合!
这是演示您所做的事情的片段:

List<int> numbers = new List<int> {5, 4};
IEnumerable<int> first = numbers.Take(1);
Console.WriteLine(first.Single()); //prints 5
numbers.Sort();
Console.WriteLine(first.Single()); //prints 4!

您创建的所有集合基本上与first- 在某种程度上,它们是指向位置的惰性指针ints。显然,当你打电话时ToList,问题就消除了。

你的情况比这更复杂。你的Sort是部分懒惰,正如你所建议的:首先你创建一个列表(arrSorted) 并向其添加整数。这部分并不懒惰,这就是您看到前几个元素已排序的原因。接下来,您添加剩余的元素 - 但是Concat很懒。现在,递归的出现让这个问题变得更加混乱:在大多数情况下,你的大多数元素IEnumerableare eager - 您从左侧和右侧创建列表,这些列表也主要由 eager + lazy tail 组成。你最终会得到一个排序的List<int>,惰性连接到一个惰性指针,它应该是只是最后一个元素(之前合并了其他元素)。
这是函数的调用图 - 红色表示惰性集合,黑色表示实数:

当您更改列表时,新列表大部分保持不变,但最后一个元素是惰性的,并指向原始列表中最大元素的位置。

结果基本上不错,但它的最后一个元素仍然指向原始列表:

最后一个例子:考虑您正在更改原始列表中的所有元素。正如您所看到的,排序集合中的大多数元素保持不变,但最后一个元素是惰性的并指向新值:

var ints = new List<int> { 3,2,1 };
var mergeSortInt = new MergeSort<int>();
var sortedInts = mergeSortInt.Sort(ints);
// sortedInts is { 1, 2, 3 }
for(int i=0;i<ints.Count;i++) ints[i] = -i * 10;
// sortedInts is { 1, 2, 0 }

这是 Ideone 上的相同示例:http://ideone.com/FQVR7 http://ideone.com/FQVR7

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

List 和 IEnumerable 的区别 的相关文章

随机推荐

  • 使用 javax.xml.soap.SOAPConnection 设置套接字读取超时

    我正在使用javax xml soap API javax xml soap SOAPConnectionFactory javax xml soap SOAPConnection和朋友 对远程服务器进行 Web 服务调用 大部分都取得了巨
  • 错误 MSB3644:找不到框架“.NETFramework,Version=v5.0”的参考程序集

    当我将项目更新到 Net 5 时 我使用天蓝色管道 我在构建解决方案步骤中收到此错误 错误 MSB3644 找不到框架 NETFramework Version v5 0 的参考程序集 要解决此问题 请安装此框架版本的 SDK 或 Targ
  • 没有模型 yii2 的 ActiveForm

    我想创建ActiveForm没有模型以防万一 我确实尝试过dynamicModel但我遇到了一些错误 use yii base DynamicModel model DynamicModel validateData compact KOM
  • 比较法语字符 Î 时出现问题

    当比较 le 和 Ile 时 C 并不认为它们是相同的 string Equals le Ile StringComparison InvariantCultureIgnoreCase 对于所有其他带重音的字符 我发现比较效果很好 我还应该
  • 如何在生产模式下启动延迟作业工人

    我正在关注Railscast 延迟作业 http railscasts com episodes 171 delayed job 一切在我的机器上运行得很好 如何在生产模式下启动delayed job工人 我在用延迟工作宝石 2 1 4 h
  • 有没有办法检查游戏对象是否已被破坏?

    我正在创建一个游戏 我想在玩家死亡时显示一个面板 我尝试过不同的方法 但似乎没有一个能达到我想要的效果 using System Collections Generic using UnityEngine using UnityEngine
  • 强制 InetAddress.getHostAddress() 返回 IPv4 地址

    我正在使用一个使用的库java net InetAddress getLocalHost getHostAddress 获取我的本地IP地址 然而 这总是在我的计算机上返回 IPv6 地址 Gentoo Linux JDK 1 6 0 37
  • IOS 中选择器作为参数

    我想为每个创建的按钮提出不同的方法 我尝试在 viewDidLoad 中调用 FirstImage 方法 但它不起作用 我在 ViewDidLoad 中的选择器有问题 无法识别 FirstImage 这是一个没有参数的 void 方法 视图
  • googletrans 停止工作,出现错误“NoneType”对象没有属性“group”

    我正在尝试googletrans而且效果很好 从今天早上开始 我开始出现以下错误 我浏览了 stackoverflow 和其他网站的多篇帖子 发现我的 IP 可能被禁止使用该服务一段时间 我尝试使用具有不同 IP 的多个服务提供商互联网 但
  • Google Play 发布前报告 - 资源名称

    我应该如何提供 EditText 的 id 来填充 Google Play 上的预发布报告 应用程序的 Beta Alpha 版本 的凭据 我试过 id editTextLogin editTextLogin R id editTextLo
  • 在 Webcontrol 上使用“Using”块有什么问题?

    我有以下使用 using 阻止TableHeaderCell LiteralControl HyperLink and GridViewRow try finally 该代码按缩进方式工作 使用 使用 块处理控件是否存在任何问题 陷阱 如下
  • Django 文件上传

    这是视图中的代码 def index request if request method POST a request POST logging debug a title logging debug a file form UploadF
  • 如何在 Magento 中获取完整的产品图片 url

    如何获取完整的产品图片 urlmagento 我需要将数据从magento迁移到django所以我需要得到产品完整图像网址迁移站点 这是我的代码
  • Android L——在视图上播放波纹效果

    我试图在某个时间在视图上 而不是在被触摸的视图上 发挥连锁反应 来自 Android L 具体来说 当用户成功更改某些文本时 我希望某个视图播放绿色波纹效果以显示成功 有什么办法可以做到这一点吗 我尝试将 RippleDrawable 放入
  • Visual Studio 诊断工具 - 如何更改选定的进程?

    我在用着Diagnostic Tools在 Visual Studio 2015 中调试 SharePoint Web 部件 我依附于一些w3wp exe处理并且窗口显示以下消息 Multiple processes are being d
  • 在 Visual Studio 中创建一个新的 TypeScript 项目

    如何开始在 Visual Studio 中编写 TypeScript 项目 当我创建一个新项目时没有这个选项 我安装了 Visual Studio 2012 以及 TypeScript 插件 我刚刚找到了解决方案 手动安装 VS Exten
  • D3D11CreateDevice() 返回垃圾值并失败

    我刚刚开始用这本书学习直接3D使用 DirectX11 进行 3D 游戏编程 我按照第一个教程进行操作 并收到一个消息框 显示 D3D11CreateDevice Failed 我检查了这个函数的返回值 得到了垃圾值 2005270483
  • 如何在vb.net中查看设计器代码

    我想看看设计师代码 我想看看如何使用或扩展表单生成 myForm 我的意思是在 C 中我可以看到 Designer cs 文件中的代码 但在 vb net 中我看不到 在 VB Net 中 为了查看设计器文件 您必须单击解决方案资源管理器上
  • 报告本地时间而不是 UTC 服务器时间

    我创建了一个页面 其中向用户显示服务器报告的天气数据 时间保存为 UTC 如何从 Blazor 服务器应用程序显示本地用户或浏览器的时间 我遇到了类似的问题并创建了一个名为的库布拉佐尔时间 https github com dustout
  • List 和 IEnumerable 的区别

    在实现这个通用的同时归并排序 http en wikipedia org wiki Merge sort 作为一种代码卡塔 http en wikipedia org wiki Kata 28programming 29 我偶然发现了 IE