使用LINQ查找数组中的最小和最大日期?

18

我有一个包含Date属性的类数组,例如:

class Record
{
    public DateTime Date { get; private set; }
}

void Summarize(Record[] arr)
{
    foreach (var r in arr)
    {
        // do stuff 
    }
}

我需要在这个数组中找到最早的和最晚的日期。

如何使用LINQ实现?


1
“efficient”和“optimal”需要上下文。您更喜欢一个在空间方面(内存使用,代码大小)或时间方面(运行时间,编译时间)高效的算法? - EricSchaefer
5个回答

42

3
最易读的方法无疑是最好的选择。就纯效率而言,这可能不是最高效的方法。尽管如此,我怀疑这段代码会成为瓶颈。 - Keith Rousseau
@Keith Rousseau:为什么你认为这不会是“最有效”的呢? - Tamas Czinege
4
它会对数组进行两次迭代。复杂度相同,常数因子加倍,不过。 - Joey
@Keith Rousseau和大家:小心微观优化。仅在您确定存在问题时进行优化。在确保不存在问题之前,请始终以可读性/可维护性为重。在大多数情况下,此解决方案已经足够好了。 - Brian Genisio
@Brian:我并不是说你应该优化这段代码。我只是指出,从纯效率的角度来看,它并不是最高效的。 - Keith Rousseau
@Keith Rousseau:如果数据存储在数据库中,arr是ORM的懒查询,那么上面的代码可能会导致针对具有日期列索引的表的两个选择语句。那么这将是最快的方法。但是,在发布者的情况下,它可能是一个包含5个元素的ArrayList,所以谁在乎两次枚举呢? - Douglas

15

没有使用LINQ的老派解决方案:

DateTime minDate = DateTime.MaxValue;
DateTime maxDate = DateTime.MinValue;
foreach (var r in arr) 
{
    if (minDate > r.Date)
    {
        minDate = r.Date;
    }
    if (maxDate < r.Date)
    {
        maxDate = r.Date;
    }
}

6
好的,针对这位点踩者,原始问题是“使用C#”,后来被编辑为“使用LINQ”。 - Natrium
实际上,你搞混了:(minDate > r.Date)和(maxDate < r.Date)。否则最小值和最大值将被交换。 - abatishchev

4
两合一的LINQ查询(以及一次遍历):
arr.Aggregate(
    new { MinDate = DateTime.MaxValue,
          MaxDate = DateTime.MinValue },
    (accDates, record) => 
        new { MinDate = record.Date < accDates.MinDate 
                        ?  record.Date 
                        : accDates.MinDate,
              MaxDate = accDates.MaxDate < record.Date 
                        ?  record.Date 
                        : accDates.MaxDate });

非常有趣!您能否看一下我的下一个问题http://stackoverflow.com/questions/2138391/how-to-rewrite-several-independent-linq-quries-into-single-one-using-aggregate,如果您能回答并且我可以接受它,我会很高兴的。 - abatishchev

1

使用Lambda表达式:

void Summarise(Record[] arr)
{
    if (!(arr == null || arr.Length == 0))
    {
        List<Record> recordList = new List<Record>(arr);
        recordList.Sort((x,y) => { return x.Date.CompareTo(y.Date); });

        // I may have this the wrong way round, but you get the idea.
        DateTime earliest = recordList[0];
        DateTime latest = recordList[recordList.Count];
    }
}

基本上:

  • 按日期顺序排序到新列表中
  • 选择该列表的第一个和最后一个元素

更新: 经过思考,如果您在乎性能,我不确定这是否是正确的方法,因为对整个列表进行排序将导致比仅扫描最高/最低值更多的比较。


1

我会创建两个属性Min和Max,将它们赋值为您添加到数组中的第一个项目的值,然后每次添加新项目时,只需检查其DateTime是否小于或大于Min Max。

这种方法快速而且高效,比每次需要获取Min Max时迭代整个数组要快得多。


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