在lambda表达式中,yield return是什么意思?

6
以下代码将列表分成以“ [”开头和“]”结尾的子列表。如何将其转换为使用yield return,以便可以懒惰地处理非常大的流输入?--或者如何在F#中实现它并进行懒惰枚举?--(不要紧,我认为F#实现应该很简单)
var list = new List<string> { "[", "1", "2", "3", "]", "[", "2", "2", "]", "[", "3", "]" };
IEnumerable<IEnumerable<string>> result = Split(list);

static IEnumerable<IEnumerable<string>> Split(List<string> list)
{
    return list.Aggregate(new List<List<string>>(), // yield return?
    (sum, current) =>
    {
        if (current == "[")
            sum.Add(new List<string>());
        else if (current == "]")
            return sum; // Convert to yield return?
        else
            sum.Last().Add(current);
        return sum; // Convert to yield return?
    });
}

感觉聚合函数在这里不太适用。请编写自己的版本,然后在其上叠加逻辑。 - leppie
1
@leppie Aggregate 的问题在于它实际上并没有聚合任何东西。Lambda 表达式仅用于其副作用,因此它只不过是一个更难读的 foreach 循环。 - Servy
4个回答

12

C#不支持匿名迭代器块,因此您需要使用命名方法而不是匿名方法。

public static IEnumerable<IEnumerable<string>> Split(IEnumerable<string> tokens)
{
    using(var iterator = tokens.GetEnumerator())
        while(iterator.MoveNext())
            if(iterator.Current == "[")
                yield return SplitGroup(iterator);
}

public static IEnumerable<string> SplitGroup(
    IEnumerator<string> iterator)
{
    while(iterator.MoveNext() && iterator.Current != "]")
        yield return iterator.Current;
}

请参见 https://dev59.com/f3M_5IYBdhLWcg3wzmrL - StayOnTarget

1

虽然C#不允许在lambda表达式中使用yield,但我认为我们可以像这样解决问题。

static IEnumerable<IEnumerable<string>> Split(List<string> list)
{
    var tmp = list as IEnumerable<string>;
    while(tmp.FirstOrDefault() == "[")
    {
        yield return tmp.TakeWhile((current) => current != "]");
        tmp = tmp.SkipWhile((current) => current != "]");
    }
}

-2

你的任务最简单的解决方案是这个方法:

IEnumerable<IEnumerable<string>> SplitList(IEnumerable<string> list, string open = @"[", string close = @"]") {
    Dictionary<int, List<string>> splitedList = new Dictionary<int, List<string>>();
    int i = 0;            
    foreach (var s in list) {
        if (open.Equals(s))
            splitedList.Add(i, new List<string>());
        else if (close.Equals(s))
            i++;
        else
            splitedList[i].Add(s);
    }
    return splitedList.Values;
}

你没有理解实际问题。 - Gert Arnold

-3
我找到另一种方法来做这件事,使用 Linq。不确定效率如何,但它可以工作。
int index=0;
list.Select(item=> new { item=item, index= item=="]"? ++index : index })
                  .Where(c => !(c.item == "[" || c.item =="]"))
                  .GroupBy(g=>g.index)
                  .Select(e=> e.Select(c=>c.item));

正在工作中 示例


这并不是惰性生成序列。Groupby需要在产生任何结果之前处理整个序列,而OP已经说他们不想这样做。 - Servy

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接