.NET 4.0中是否有序列运算符实现?

时间:2010-06-29 07:54:56

标签: linq .net-4.0 sequences lazy-sequences

我的意思是类似于Linq join,group,distinct等,只处理值序列,而不是集合。

序列和集合之间的区别在于序列的长度可能是无限的,而集合是有限的。

让我举个例子:

var c1 = new[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
var c2 = FunctionThatYieldsFibonacciNumbers();

var c3 = c1.Except(c2);

这不起作用。 Except的实现不能在任何集合中的数字严格上升或下降的基础上工作,因此它首先尝试将第二个集合中的所有值收集到一个集合(或类似)中,并且仅在此之后才会开始枚举第一个集合。

假设上面的函数只是一个不会终止的While循环,除非你明确地停止枚举它,上面的代码将因内存不足而失败。

但是,鉴于我有一些被认为是严格升序或降序的集合,.NET 4.0中是否有任何可以实现的实现:

  1. 给我两个共同的值(内连接)
  2. 给我两个(联合/外连接)的所有值
  3. 按顺序#2
  4. 给出序列#1中的所有值

    我需要这种与我需要构建的调度系统相关的功能,我需要做以下事情:

    c1 = the 1st and 15th of every month from january 2010 and onwards
    c2 = weekdays from 2010 and onwards
    c3 = all days in 2010-2012
    c4 = c1 and c2 and c3
    

    这基本上可以让我在2010年到2012年的每个月的第1和第15天,但只有当这些日期在工作日时才会出现。

    使用这些函数可以更容易地生成有问题的值而无需显式地构建它们的集合。在上面的示例中,构建前两个集合需要知道第三个集合的约束,并且示例可能变得比上面复杂得多。

2 个答案:

答案 0 :(得分:2)

我会说LINQ运算符已经在处理一般序列 - 但它们并不是专门针对单调序列而设计的,这就是你在这里所做的。

我怀疑写这些东西不会太难 - 但我不相信任何内置的东西;据我所知,在System.Interactive中,这个场景甚至都没有。

答案 1 :(得分:1)

你可以考虑Seq module of F#,它是通过使用生成序列的1 .. 10这样的特殊F#语言结构自动调用的。它以您描述的方式支持infinite sequences,因为它允许进行惰性求值。在您的情况下使用F#可能也可能不是微不足道的。但是,直接从C#使用Seq模块应该不会太难(但我自己没有尝试过)。

以下this Mandelbrot example显示了一种通过隐藏yield在C#中使用无限序列的方法。不确定它会让你更接近你想要的东西,但它可能有所帮助。

修改
虽然你已经评论说在你当前的项目中不值得,并接受了你的问题的答案,但我对这个想法很感兴趣并且想出了一个小例子。

它似乎相当简单,并且在C#中使用.NET 3.5和.NET 4.0,通过简单地包括FSharp.Core.dll(download it for .NET 3.5)到您的引用。这是实现您的第一个用例的无限序列的开箱即用示例:

// place in your using-section:
using Microsoft.FSharp.Collections;
using Microsoft.FSharp.Core;

// [...]

// trivial 1st and 15th of the month filter, starting Jan 1, 2010.
Func<int, DateTime> firstAndFifteenth = (int i) =>
{
    int year = i / 24 + 2010;
    int day = i % 2 != 0 ? 15 : 1;
    int month = ((int)i / 2) % 12 + 1;
    return new DateTime(year, month, day);
};

// convert func to keep F# happy
var fsharpFunc = FSharpFunc<int, DateTime>.FromConverter(
                   new Converter<int, DateTime>(firstAndFifteenth));

// infinite sequence, returns IEnumerable
var infSeq = SeqModule.InitializeInfinite<DateTime>(fsharpFunc);

// first 100 dates
foreach (var dt in infSeq.Take(100))
    Debug.WriteLine("Date is now: {0:MM-dd-yyy}", dt);

输出是可以预期的,前几行是这样的:

Date is now: 01-01-2010
Date is now: 01-15-2010
Date is now: 02-01-2010
Date is now: 02-15-2010
Date is now: 03-01-2010