草庐IT

c# - 为什么 Where 和 Select 的表现优于 Select?

coder 2023-07-07 原文

我有一个类,像这样:

public class MyClass
{
    public int Value { get; set; }
    public bool IsValid { get; set; }
}

实际上它要大得多,但这会重现问题(奇怪)。

我想得到 Value 的总和,其中实例有效。到目前为止,我已经找到了两种解决方案。

第一个是这样的:

int result = myCollection.Where(mc => mc.IsValid).Select(mc => mc.Value).Sum();

然而,第二个是这样的:

int result = myCollection.Select(mc => mc.IsValid ? mc.Value : 0).Sum();

我想获得最有效的方法。起初,我认为第二个会更有效率。然后我的理论部分开始“好吧,一个是 O(n + m + m),另一个是 O(n + n)。第一个应该在更多无效的情况下表现更好,而第二个应该表现更好用更少”。我以为他们会表现得一样。 编辑:然后@Martin 指出 Where 和 Select 结合在一起,所以它实际上应该是 O(m + n)。但是,如果您往下看,这似乎与此无关。


So I put it to the test.

(超过 100 行,所以我认为最好将其作为 Gist 发布。)
结果……很有趣。

领带公差为 0%:

天平有利于 SelectWhere , 大约 30 点。

How much do you want to be the disambiguation percentage?<br/> 0<br/> Starting benchmarking.<br/> Ties: 0<br/> Where + Select: 65<br/> Select: 36<br/>

2% 领带公差:

除了一些误差在 2% 以内外,两者都是一样的。我会说这是最小误差范围。 SelectWhere现在只有大约 20 分的领先优势。

How much do you want to be the disambiguation percentage?<br/> 2<br/> Starting benchmarking.<br/> Ties: 6<br/> Where + Select: 58<br/> Select: 37<br/>

5% 领带公差:

这就是我所说的最大误差范围。它使 Select 变得更好一点, 但不多。

How much do you want to be the disambiguation percentage?<br/> 5<br/> Starting benchmarking.<br/> Ties: 17<br/> Where + Select: 53<br/> Select: 31<br/>

10% 领带公差:

这超出了我的误差范围,但我仍然对结果感兴趣。因为它给出了 SelectWhere它已经有一段时间领先 20 分了。

How much do you want to be the disambiguation percentage?<br/> 10<br/> Starting benchmarking.<br/> Ties: 36<br/> Where + Select: 44<br/> Select: 21<br/>

25% 领带公差:

这超出了我的误差范围,方式,但我仍然对结果感兴趣,因为 SelectWhere 仍然(几乎)保持他们 20 分的领先优势。它似乎在少数几个方面超越了它,这就是它领先的原因。

How much do you want to be the disambiguation percentage?<br/> 25<br/> Starting benchmarking.<br/> Ties: 85<br/> Where + Select: 16<br/> Select: 0<br/>


现在,我猜测 20 分的领先优势来自中间位置,他们肯定会在附近获得相同的表现。我可以尝试记录它,但要吸收大量信息。我想图表会更好。

这就是我所做的。

它表明 Select线保持稳定(预期)并且 Select + Where线路攀升(预期)。然而,令我困惑的是为什么它不符合 Select在 50 或更早:事实上我期望早于 50,因为必须为 Select 创建一个额外的枚举器和 Where .我的意思是,这显示了 20 分的领先优势,但并没有解释原因。我想这就是我的问题的要点。

为什么会这样?我应该相信它吗?如果没有,我应该使用另一个还是这个?


正如@KingKong 在评论中提到的,您还可以使用 Sum需要 lambda 的重载。所以我的两个选项现在变成了这样:

首先:

int result = myCollection.Where(mc => mc.IsValid).Sum(mc => mc.Value);

第二个:

int result = myCollection.Sum(mc => mc.IsValid ? mc.Value : 0);

我打算让它更短一些,但是:

How much do you want to be the disambiguation percentage?<br/> 0<br/> Starting benchmarking.<br/> Ties: 0<br/> Where: 60<br/> Sum: 41<br/> How much do you want to be the disambiguation percentage?<br/> 2<br/> Starting benchmarking.<br/> Ties: 8<br/> Where: 55<br/> Sum: 38<br/> How much do you want to be the disambiguation percentage?<br/> 5<br/> Starting benchmarking.<br/> Ties: 21<br/> Where: 49<br/> Sum: 31<br/> How much do you want to be the disambiguation percentage?<br/> 10<br/> Starting benchmarking.<br/> Ties: 39<br/> Where: 41<br/> Sum: 21<br/> How much do you want to be the disambiguation percentage?<br/> 25<br/> Starting benchmarking.<br/> Ties: 85<br/> Where: 16<br/> Sum: 0<br/>

20 分的领先优势仍然存在,这意味着它与 Where 无关和 Select @Marcin 在评论中指出的组合。

感谢您阅读我的文字墙!另外,如果您有兴趣,here's记录 Excel 接收的 CSV 的修改版本。

最佳答案

Select 在整个集合上迭代一次,并为每个项目执行条件分支(检查有效性)和 + 操作。

Where+Select 创建一个跳过无效元素的迭代器(不会 yield 它们),仅对有效元素执行 + .

因此,Select 的成本是:

t(s) = n * ( cost(check valid) + cost(+) )

对于Where+Select:

t(ws) = n * ( cost(check valid) + p(valid) * (cost(yield) + cost(+)) )

地点:

  • p(valid) 是列表中某项有效的概率。
  • cost(check valid)是检查有效性的分支的成本
  • cost(yield)where 迭代器构造新状态的代价,它比Select版本使用。

如您所见,对于给定的 nSelect 版本是常数,而 Where+Select 版本是线性的以 p(valid) 作为变量的等式。成本的实际值决定了两条线的交点,由于 cost(yield) 可以不同于 cost(+),因此它们不一定相交在 p(有效)=0.5。

关于c# - 为什么 Where 和 Select 的表现优于 Select?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18331774/

有关c# - 为什么 Where 和 Select 的表现优于 Select?的更多相关文章

  1. ruby - 为什么我可以在 Ruby 中使用 Object#send 访问私有(private)/ protected 方法? - 2

    类classAprivatedeffooputs:fooendpublicdefbarputs:barendprivatedefzimputs:zimendprotecteddefdibputs:dibendendA的实例a=A.new测试a.foorescueputs:faila.barrescueputs:faila.zimrescueputs:faila.dibrescueputs:faila.gazrescueputs:fail测试输出failbarfailfailfail.发送测试[:foo,:bar,:zim,:dib,:gaz].each{|m|a.send(m)resc

  2. ruby-on-rails - Rails - 子类化模型的设计模式是什么? - 2

    我有一个模型:classItem项目有一个属性“商店”基于存储的值,我希望Item对象对特定方法具有不同的行为。Rails中是否有针对此的通用设计模式?如果方法中没有大的if-else语句,这是如何干净利落地完成的? 最佳答案 通常通过Single-TableInheritance. 关于ruby-on-rails-Rails-子类化模型的设计模式是什么?,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.co

  3. ruby - 什么是填充的 Base64 编码字符串以及如何在 ruby​​ 中生成它们? - 2

    我正在使用的第三方API的文档状态:"[O]urAPIonlyacceptspaddedBase64encodedstrings."什么是“填充的Base64编码字符串”以及如何在Ruby中生成它们。下面的代码是我第一次尝试创建转换为Base64的JSON格式数据。xa=Base64.encode64(a.to_json) 最佳答案 他们说的padding其实就是Base64本身的一部分。它是末尾的“=”和“==”。Base64将3个字节的数据包编码为4个编码字符。所以如果你的输入数据有长度n和n%3=1=>"=="末尾用于填充n%

  4. ruby - 解析 RDFa、微数据等的最佳方式是什么,使用统一的模式/词汇(例如 schema.org)存储和显示信息 - 2

    我主要使用Ruby来执行此操作,但到目前为止我的攻击计划如下:使用gemsrdf、rdf-rdfa和rdf-microdata或mida来解析给定任何URI的数据。我认为最好映射到像schema.org这样的统一模式,例如使用这个yaml文件,它试图描述数据词汇表和opengraph到schema.org之间的转换:#SchemaXtoschema.orgconversion#data-vocabularyDV:name:namestreet-address:streetAddressregion:addressRegionlocality:addressLocalityphoto:i

  5. ruby - 为什么 4.1%2 使用 Ruby 返回 0.0999999999999996?但是 4.2%2==0.2 - 2

    为什么4.1%2返回0.0999999999999996?但是4.2%2==0.2。 最佳答案 参见此处:WhatEveryProgrammerShouldKnowAboutFloating-PointArithmetic实数是无限的。计算机使用的位数有限(今天是32位、64位)。因此计算机进行的浮点运算不能代表所有的实数。0.1是这些数字之一。请注意,这不是与Ruby相关的问题,而是与所有编程语言相关的问题,因为它来自计算机表示实数的方式。 关于ruby-为什么4.1%2使用Ruby返

  6. ruby - ruby 中的 TOPLEVEL_BINDING 是什么? - 2

    它不等于主线程的binding,这个toplevel作用域是什么?此作用域与主线程中的binding有何不同?>ruby-e'putsTOPLEVEL_BINDING===binding'false 最佳答案 事实是,TOPLEVEL_BINDING始终引用Binding的预定义全局实例,而Kernel#binding创建的新实例>Binding每次封装当前执行上下文。在顶层,它们都包含相同的绑定(bind),但它们不是同一个对象,您无法使用==或===测试它们的绑定(bind)相等性。putsTOPLEVEL_BINDINGput

  7. ruby - Infinity 和 NaN 的类型是什么? - 2

    我可以得到Infinity和NaNn=9.0/0#=>Infinityn.class#=>Floatm=0/0.0#=>NaNm.class#=>Float但是当我想直接访问Infinity或NaN时:Infinity#=>uninitializedconstantInfinity(NameError)NaN#=>uninitializedconstantNaN(NameError)什么是Infinity和NaN?它们是对象、关键字还是其他东西? 最佳答案 您看到打印为Infinity和NaN的只是Float类的两个特殊实例的字符串

  8. ruby-on-rails - 如果 Object::try 被发送到一个 nil 对象,为什么它会起作用? - 2

    如果您尝试在Ruby中的nil对象上调用方法,则会出现NoMethodError异常并显示消息:"undefinedmethod‘...’fornil:NilClass"然而,有一个tryRails中的方法,如果它被发送到一个nil对象,它只返回nil:require'rubygems'require'active_support/all'nil.try(:nonexisting_method)#noNoMethodErrorexceptionanymore那么try如何在内部工作以防止该异常? 最佳答案 像Ruby中的所有其他对象

  9. ruby - 为什么 SecureRandom.uuid 创建一个唯一的字符串? - 2

    关闭。这个问题需要detailsorclarity.它目前不接受答案。想改进这个问题吗?通过editingthispost添加细节并澄清问题.关闭8年前。Improvethisquestion为什么SecureRandom.uuid创建一个唯一的字符串?SecureRandom.uuid#=>"35cb4e30-54e1-49f9-b5ce-4134799eb2c0"SecureRandom.uuid方法创建的字符串从不重复?

  10. ruby-on-rails - rspec should have_select ('cars' , :options => ['volvo' , 'saab' ] 不工作 - 2

    关闭。这个问题需要detailsorclarity.它目前不接受答案。想改进这个问题吗?通过editingthispost添加细节并澄清问题.关闭8年前。Improvethisquestion在首页我有:汽车:VolvoSaabMercedesAudistatic_pages_spec.rb中的测试代码:it"shouldhavetherightselect"dovisithome_pathit{shouldhave_select('cars',:options=>['volvo','saab','mercedes','audi'])}end响应是rspec./spec/request

随机推荐