2

我的意思是类似于 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. 给我序列#1中所有不在序列#2中的值

我需要这种与我需要构建的调度系统相关的功能,我需要在其中执行以下操作:

c1 = 2010 年 1 月起每月的 1 号和 15 号
c2 = 2010 年及以后的工作日
c3 = 2010-2012 年的所有天数
c4 = c1 和 c2 和 c3

从 2010 年到 2012 年,这基本上会给我每个月的第 1 天和第 15 天,但前提是这些日期是在工作日。

有了这样的函数,生成有问题的值会容易得多,而无需明确地从它们中构建集合。在上面的示例中,构建前两个集合需要知道第三个集合的约束,并且示例可能变得比上面的复杂得多。

4

2 回答 2

2

我想说 LINQ 运算符已经在一般序列上工作了——但它们并不是专门为单调序列而设计的,这就是你在这里所得到的。

我怀疑写这样的东西不会太难——但我不相信任何东西是内置的;据我所知,在 System.Interactive 中甚至没有任何适用于这种场景的东西。

于 2010-06-29T07:58:44.930 回答
1

您可能会想到F# 的 Seq 模块,它通过使用特殊的 F# 语言结构(例如1 .. 10生成序列)自动调用。它支持您描述的无限序列,因为它允许延迟评估。在您的情况下,使用 F# 可能会或可能不会微不足道。但是,直接从 C# 中使用 Seq 模块应该不会太难(但我自己没有尝试过)。

下面这个 Mandelbrot 示例展示了一种通过隐藏在 C# 中使用无限序列的方法yield。不确定它是否能让你更接近你想要的,但它可能会有所帮助。

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

通过简单地将 FSharp.Core.dll (为 .NET 3.5 下载)添加到您的参考资料中,它似乎相当简单,并且在带有 .NET 3.5 和 .NET 4.0 的 C# 中运行良好。这是实现您的第一个用例的无限序列的开箱即用示例:

// 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);

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

日期现在:01-01-2010
日期现在:01-15-2010
日期现在:02-01-2010
日期现在:02-15-2010
日期现在:03-01-2010
于 2010-06-29T08:12:52.543 回答