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 的区别 的相关文章

  • 异步提交或回滚事务范围

    正如许多人所知 TransactionScope当async await Net 中引入了模式 如果我们尝试使用一些它们就会损坏await在事务范围内调用 现在这个问题已经解决了 感谢范围构造函数选项 a 17527759 1178314
  • WebBrowser Control 导致整个应用程序变得无响应

    我有一个带有嵌入式 Web 浏览器的 C NET 3 5 应用程序 浏览器被设计为指向远程站点 而不是本地站点 一切工作正常 但是当页面响应缓慢时 这会导致我的整个应用程序变得无响应 直到加载页面 我不介意浏览器在执行任务时没有响应 但应用
  • 以编程方式获取命名管道的系统名称

    我正在使用 WCF NetNamedPipeBinding 编写进程间通信 我的目标是让服务在 net pipe localhost service 上运行 所以我运行最简单的主机 host new ServiceHost contract
  • 隐式将 string 转换为 string_view

    void Foo1 string view view string str one two three Foo1 one two three Implicitly convert char to string view Foo1 str I
  • 输出 objdump -t 的输出中的“.hidden”是什么意思?

    Example objdump Logger cpp o t 00000000 g F text 00000000 hidden sti 10 Logger cpp 0b2ae32b 这意味着符号的可见性被隐藏 https develope
  • 如何将 int.TryParse 与可为空的 int 一起使用? [复制]

    这个问题在这里已经有答案了 我正在尝试使用 TryParse 来查找字符串值是否为整数 如果该值为整数 则跳过 foreach 循环 这是我的代码 string strValue 42 if int TryParse trim strVal
  • tmpnam 的 C/C++ 线程安全性?

    我需要使用tmpnamC 中的函数 但我需要了解它的线程安全性 也就是说 如果我有多个线程 每个线程都需要为临时文件获取不同的名称 我是否可以保证每个线程都会收到具有不同名称的文件 tmpnam 仅保证该文件当时不存在 但它可能会在您自己创
  • 当假设 [[assume]] 包含 UB 时会发生什么?

    在 C 23 中 assume expression 属性使得如果表达 is false 行为未定义 例如 int div int x int y assume y 1 return x y 这会编译成相同的代码 就像y一直是1 div i
  • Web API 2 中的方法名称约定 [关闭]

    Closed 这个问题需要多问focused help closed questions 目前不接受答案 是否有 Web API 2 中使用的约定的列表 以这两种方法为例 两者都可以工作 但都没有用属性来装饰 IHttpActionResu
  • DirectX Vertex 中的 THE 是什么

    我知道 RHW 是倒数同质 W 但有人可以解释一下它的使用方法和作用吗 gamedev论坛上的说明post http www gamedev net topic 440283 reciprocal of homogeneous w and
  • 使用 C 通过引用传递数组

    是的 我已经阅读了这个问题和答案 在 C 中通过引用传递数组 https stackoverflow com questions 1106957 pass array by reference in c 我有一个类似的问题 并从该问题中实现
  • 如何用C语言创建字典?

    我正在用 C 语言编写一个微控制器 作为它的一部分 我想在 7 段显示器上显示某些字母 每个字母都有一个对应的数字 使 7 段显示屏显示该字母 它没有真正的模式 因为数字只是通过将显示字母所需的 7 段显示器上的位相加而成 因此如果我可以创
  • try-catch 块是否会降低性能[重复]

    这个问题在这里已经有答案了 This link http www cplusplus com doc tutorial exceptions states 为了捕获异常 我们必须将一部分代码放在异常下 检查 这是通过将这部分代码包含在 tr
  • C# 从字符串变量中获取类型并在泛型方法中使用它

    我希望能够通过某种方式 即从数据库 获取我收到的字符串值的实际类型 这样我就可以在通用方法中使用该类型 例如DoSomething
  • 如何收集和存储tellp()、tellg()返回类型?

    我正在编写一个在文件中维护 linked list 的程序 因此 我通过使用tellp tellg 遍历文件并将其添加到特定的长整数 可以视为偏移量 以到达新位置 一个简单的例子是 long next offset sizeof long
  • 使用循环在 C 中管道传输两个或多个 shell 命令

    我正在尝试执行ls wc l通过 C 语言程序 而不是使用命令行 这是我当前的工作代码 int main int pfds 2 pipe pfds pid t pid fork if pid 0 The child process clos
  • timeval_subtract 解释

    使用 timeval subtract 函数来查找两个 struct timeval 类型之间经过的时间 有人可以解释一下用于 通过更新 y 执行后续减法的进位 和其他部分的目的和逐步数学吗 我了解该函数的目的以及如何在程序中实现它 但我想
  • 如何将 .ashx 处理程序与 asp:Image 对象一起使用?

    我有一个 ashx 处理程序 using System using System Web public class Thumbnail IHttpHandler public void ProcessRequest HttpContext
  • 并排显示图像的一半 - OpenGL

    我为两个图像创建了两个纹理 现在我想在opengl中按图像2的左侧部分 完整的图像1 图像2的右侧部分的顺序显示该纹理 我已经做了如下 Image1 显示在 opengl 屏幕的中央 但屏幕的左右部分不正确 应分别显示 image2 的左侧
  • 我的 Visual Studio 2008 模板有什么问题?

    我正在尝试为 Visual Studio 创建自己的类模板 称为 公共类 我跟着有关如何手动创建项目模板的官方 MSDN 说明 http msdn microsoft com en us library ms247113 aspx几乎一字不

随机推荐

  • 使用 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