收益率很高?

时间:2010-10-03 23:28:54

标签: c#

我发现自己经常使用IEnumerables,以便我可以返回每个结果。有没有办法压缩像这样的东西

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

要删除内在的foreach?

6 个答案:

答案 0 :(得分:61)

这是C#不支持的频繁请求的功能。有关详细信息,请参阅此Connect项目:

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ω:

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

您可能还想阅读Cω实现者关于该功能的这篇论文:

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

如果您对支持此功能的非C#语言感兴趣,请查看“yield!” F#的特点。 (我只是喜欢这个功能的名称是“收益!”)

即使您对理论上的东西不感兴趣,但听起来您将这种情况视为一个实际问题。你还应该阅读Wes Dyer关于有效地进行这种嵌套迭代的技术的文章,而没有“收益预告”:

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

答案 1 :(得分:17)

不,除非您使用LINQ将yield return语句完全替换为return语句,否则不存在。

例如:

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

答案 2 :(得分:3)

使用Enumerable.SelectMany

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

仅当您的方法中没有任何其他yield return语句时才有效。

答案 3 :(得分: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);
  }
}

使用Eric Lippert的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,而外部方法只需要平整这个结果。

答案 4 :(得分:0)

使用Linq的力量!

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

答案 5 :(得分:0)

在C#7.0中,允许使用局部函数,这使我们能够采用一种相当整齐的方法

IEnumerable<T> FlatEnumerable(){
    IEnumerable<IEnumerable<T>> NestedEnumerable(){
       yield return myEnumerable1;
       yield return myEnumerable2;
    }

    return NestedEnumerable().SelectMany(e => e);
}

https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/local-functions