2010-10-03 75 views
40

我發現我自己對IEnumerables進行了大量的研究,以便我可以返回每個結果。有沒有辦法像這樣壓縮產量回報多?

foreach (var subSelector in subSelectors) 
{ 
    foreach (var node in FindSingle(context, subSelector)) 
     yield return node; 
} 

要刪除內部的foreach?

+0

這已被問了很多次,應該合併。搜索「yield multiple enumerable」 – mafu 2010-10-03 23:35:00

+0

@mafutrct:*沒有找到「yield multiple enumerable」的結果。*您能舉一個例子嗎? – 2010-10-03 23:40:42

+1

這是我發現(授予,與不同的搜索短語):http://stackoverflow.com/questions/2055927/ienumerable-and-recursion-using-yield-return,http://stackoverflow.com/questions/ 1824934/rewrite-this-foreach-yield-to-a-linq-yield,http://stackoverflow.com/questions/1270024/nested-yield-return-with-ienumerable。但是,我沒有找到我正在尋找的問題,這個問題確切地解釋了要求的內容。我還記得前一段時間曾問過這個問題......我會嘗試在我的Q列表中查看它。 – mafu 2010-10-04 09:56:22

回答

14

不,不存在,除非您完全使用LINQ將單個return聲明全部替換爲yield return

例如:

return someSet 
    .Concat(someOtherSet.SelectMany(s => FindSingle(context, s)); 
3

使用Enumerable.SelectMany

return subSelectors.SelectMany(subselector => FindSingle(context, subSelector)); 

這隻能如果你沒有在你的方法的任何其他收益率return語句。

+10

是的......但是在那之後你不能再產生任何東西。 – mpen 2010-10-03 23:35:19

52

這是C#不支持的有點頻繁的功能。有關詳細信息,請參閱本連接項目:

http://connect.microsoft.com/VisualStudio/feedback/details/256934/yield-return-to-also-yield-collections

所提出的語法通常是這樣的:

public static IEnumerable<T> PreorderTraversal<T>(this BinaryTree<T> root) 
{ 
    if (root == null) yield break; 
    yield return root.Item; 
    yield foreach root.Left.PreorderTraversal(); 
    yield foreach root.Right.PreorderTraversal(); 
} 

如果您有興趣與支持此功能類似C#語言播放,採取看看C-Omega:

http://research.microsoft.com/en-us/um/cambridge/projects/comega/

你也可能需要閱讀對T本文他功能,通過C-Omega的實現者:

http://research.microsoft.com/en-us/projects/specsharp/iterators.pdf

如果你有興趣在支持此功能的非類似C#語言,看看在「屈服!」 F#的功能。 (我只是喜歡該功能的名稱是「屈服!」)

即使你對理論的東西不感興趣,這聽起來像你面臨這種情況作爲一個實際問題。你也應該閱讀韋斯·戴爾對技術的文章,有效地做這樣的嵌套迭代不「屈服的foreach」:

http://blogs.msdn.com/b/wesdyer/archive/2007/03/23/all-about-iterators.aspx

+0

我以爲Comega已經集成到C#中,所以他們停止開發它。它是否繼續爲未來的C#版本帶來新的想法? – 2010-10-04 17:03:53

+1

@Joan:來自C-omega的一些想法已經被整合到C#中,其中一些還沒有。無論研究還是發展,我都不知道。 – 2010-10-04 18:48:10

+7

我認爲只是'收益'聽起來會更好。感謝你的回答!這很有趣。 – mpen 2010-10-06 09:08:12

2

您可以打破你的方法一分爲二。鑑於這些擴展方法:

public static class MultiEnumerableExtensions { 
    public static IEnumerable<T> Pack<T>(this T item) { 
    yield return item; 
    } 
    public static IEnumerable<T> Flatten<T>(
    this IEnumerable<IEnumerable<T>> multiList) { 
    return multiList.SelectMany(x => x); 
    } 
} 

而且使用埃裏克利珀的example,就變成這樣:

public static class BinaryTreeExtensions { 
    public static IEnumerable<T> PreorderTraversal<T>(this BinaryTree<T> root) { 
    return PreorderTraversalMulti(root).Flatten(); 
    } 
    private static IEnumerable<IEnumerable<T>> PreorderTraversalMulti<T>(
    this BinaryTree<T> root) { 
    if (root == null) yield break; 
    yield return root.Item.Pack(); // this packs an item into an enumerable 
    yield return root.Left.PreorderTraversal(); 
    yield return root.Right.PreorderTraversal(); 
    } 
} 

內方法產生的T,而不是TS的枚舉接口,與外部方法只需要扁平化這一結果。

+0

對於少量語法糖來說,看起來像是一個很大的開銷。我欣賞這個建議,但它*很有趣。 – mpen 2010-10-06 09:06:54

+0

有可能是一個門檻,它使用它是有意義的。可能如果你的方法中有多個「foreach yield」。我認爲埃裏克的例子很少有資格。其他人可能會認爲不然。 – 2010-10-06 13:11:44

0

使用Linq的力量!

return subSelectors.SelectMany(s => FindSingle(context, s));