[英]F# yield! operator - Implementation and possible C# equivalents
我正在學習F#,我真的很喜歡yield!
(yield-bang)運營商。 不僅因為它的名字,而且它當然也是它的作用。
yield!
operator基本上允許您從序列表達式中生成序列的所有元素。 這對於編寫枚舉器很有用。 由於我經常遇到大而復雜的調查員,我對策略很感興趣,我們可以用它來分解它們,並從簡單的枚舉器中編寫它們。
不幸的是, yield!
運算符在C#中不可用。 據我所知,它的作用就像foreach (var x in source) yield x;
但是我正在閱讀的這本書( Petricek的真實世界F# - 曼寧 )表明它有更好的表現......
為了在C#中實現類似的構造,我已經探索了多種方法,但它們都沒有像yield!
一樣簡潔yield!
操作員,我也不確定它們的復雜性。 如果我的BigO號碼正確,有人可以提供輸入嗎?
將枚舉器分解為多個私有枚舉器,然后從公共枚舉器中生成每個元素:
foreach (var x in part1()) yield x foreach (var x in part2()) yield x
這將有效地導致每個元素的“雙倍收益”。 那是O(2n)嗎? (或者可能更糟?)無論如何,使用這種方法阻止我使用yield break;
來自我的任何子部分。
將枚舉器分解為多個私有枚舉器,然后從公共枚舉器中連接所有私有枚舉器:
return part1().Concat(part2())
我相信這與上述解決方案沒有什么不同,因為Concat()
是按照我上面概述的方式實現的。
還有其他選擇嗎?
在當前版本的C#中,我認為除了foreach... yield return
之外你還有其他選擇foreach... yield return
和Concat
。 我同意yield!
會很高興yield!
C#中的運算符,它會使某些結構更加優雅,但我懷疑這個功能是否會成為“必備”列表,因為我們可以很容易地將其刪除。
您可能對此MS研究論文感興趣,該論文介紹了一種新的yield foreach
構造:
IEnumerable<XmlNode> Traverse(XmlNode n)
{
yield return n;
foreach (XmlNode c in n.ChildNodes)
yield foreach Traverse(c);
}
關於復雜性的問題:在兩種情況下都是O(n) 。 不使用O(2n) ,因為它表示與O(n) (線性)相同的復雜度。 我認為你不能用當前的C#功能做得更好......
關於編譯器如何轉換yield!
操作,Thomas Levesque在他的回答中引用的論文說明了4.3節中的一種實現技術(特別是,他們的示例跨越圖7-9說明了一般策略)。 我不認為在C#中的迭代器塊中有任何好方法可以做到這一點 - 因為我理解你提出的解決方案,它們在遞歸使用時都會導致二次行為。 您總是可以手動創建NestedEnumerable<T>
子類來實現性能優勢,但與使用普通迭代器塊相比,這將非常難看。
yield!
沒有直接的對應物yield!
在C#中。 你現在仍然堅持使用foreach
和yield return
。
但是,IIRC,LINQ提供類似的東西,即SelectMany
查詢運算符,它將C#轉換為from .. in ..
子句中的多個。
(我希望我不會混淆兩個不同的概念,但是IIRC,兩者都yield!
而SelectMany
基本上是“扁平化”投影;即,對象的層次結構被“扁平化”為一個列表。)
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.