一次通过多个IEnumerable

问题描述 投票:-1回答:1

是否有可能编写一个使IEnumerable被多次使用而仅一次通过而又不将所有数据读入内存的高阶函数?

例如,在下面的代码中,可枚举是mynums(为了方便枚举,我在上面标记了.Trace())。目的是确定是否有大于5的数字以及所有数字的总和。处理两次可枚举的函数为Both_TwoPass,但将其枚举两次。相反,Both_NonStream仅枚举一次,但以将其读入内存为代价。原则上,可以像Any5Sum所示以一次通过和以流方式执行这两项任务,但这是特定的解决方案。是否可以编写一个具有与Both_*相同签名的函数,但这是两全其美的方法?

(在我看来这应该可以使用线程。是否有更好的解决方案,例如使用async?]

using System;
using System.Collections.Generic;
using System.Linq;

namespace ConsoleApp
{
    static class Extensions
    {
        public static IEnumerable<T> Trace<T>(this IEnumerable<T> tt, string msg = "")
        {
            Console.Write(msg);
            try
            {
                foreach (T t in tt)
                {
                    Console.Write(" {0}", t);
                    yield return t;
                }
            }
            finally
            {
                Console.WriteLine('.');
            }
        }

        public static (S1, S2) Both_TwoPass<T, S1, S2>(this IEnumerable<T> tt, Func<IEnumerable<T>, S1> f1, Func<IEnumerable<T>, S2> f2)
        {
            return (f1(tt), f2(tt));
        }

        public static (S1, S2) Both_NonStream<T, S1, S2>(this IEnumerable<T> tt, Func<IEnumerable<T>, S1> f1, Func<IEnumerable<T>, S2> f2)
        {
            var tt2 = tt.ToList();
            return (f1(tt2), f2(tt2));
        }

        public static (bool, int) Any5Sum(this IEnumerable<int> ii)
        {
            int sum = 0;
            bool any5 = false;
            foreach (int i in ii)
            {
                sum += i;
                any5 |= i > 5; // or: if (!any5) any5 = i > 5;
            }
            return (any5, sum);
        }

    }
    class Program
    {
        static void Main()
        {
            var mynums = Enumerable.Range(0, 10).Trace("mynums:");
            Console.WriteLine("TwoPass: (any > 5, sum) = {0}", mynums.Both_TwoPass(tt => tt.Any(k => k > 5), tt => tt.Sum()));
            Console.WriteLine("NonStream: (any > 5, sum) = {0}", mynums.Both_NonStream(tt => tt.Any(k => k > 5), tt => tt.Sum()));
            Console.WriteLine("Manual: (any > 5, sum) = {0}", mynums.Any5Sum());
        }
    }
}
c# ienumerable
1个回答
0
投票

您绝对可以在foreach中调用任意数量的操作。我不确定您要查找哪种语法,但是您似乎在询问基本嵌套的foreach和操作列表:

public static void CallManyActions<T>(IEnumerable<T> tt,
      params Action<T>[] actions)
{
    foreach (var t in tt)
    {
        foreach (var a in actions)
        {
            a(t);
        }
    }
}

并称呼它

var mynums = Trace(Enumerable.Range(0, 10),"mynums:");

var sum = 0;
var has5 = false;
CallManyActions(mynums, (x => sum +=x), (i => has5 |= (i>5)));

如果您只使用LINQ,请查看Enumerable.Aggregate调用中的多项操作。

© www.soinside.com 2019 - 2024. All rights reserved.