views:

832

answers:

5

I have an array of classes with a property Date, i.e.:

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

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

I have to find the earliest (minimum) and the latest (maximum) dates in this array.

How can I do that using LINQ?

+15  A: 

If you want to find the earliest or latest Date:

DateTime earliest = arr.Min(record => record.Date);
DateTime latest   = arr.Max(record => record.Date);

Enumerable.Min, Enumerable.Max


If you want to find the record with the earliest or latest Date:

Record earliest = arr.MinBy(record => record.Date);
Record latest   = arr.MaxBy(record => record.Date);

See: How to use LINQ to select object with minimum or maximum property value

dtb
Definitely the most readable way to go. In terms of pure efficiency that wouldn't be the most efficient. I doubt this piece of code would be a bottleneck, though.
Keith Rousseau
@Keith Rousseau: Why makes you think that this wouldn't be the "most efficient"?
DrJokepu
@drj: It iterates the array twice. Same complexity, constant factor doubled, though.
Joey
@Keith Rousseau et all: Beware of micro optimizations. Only optimize if you know that it is a problem. Side with readability/maintainability until/unless you know it is a problem. In MOST cases, this solution is plenty fine.
Brian Genisio
@Brian: I'm not saying that you should optimize this piece of code. I was just pointing out that from a pure efficiency standpoint, it is not the most efficient.
Keith Rousseau
@Keith Rousseau: if the data was stored in a database, and arr was a lazy query against an ORM, then the above code might result in two select statements against a table with an index on the date column. Then this would be the fastest way. But, yes, in the poster's case, it's probably an ArrayList with 5 elements, so who cares about enumerating twice?
Douglas
+10  A: 

old school solution without 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;
    }
}
Natrium
ok, for the downvoter: the original quetion was: `with C#`, and was edited to `with LINQ`
Natrium
@Natrium: In fact, you got confused: (minDate > r.Date) and (maxDate < r.Date). Otherwise minimal and maximum will be swaped.
abatishchev
@abatishchev: you are absolutely right and I corrected this.
Natrium
+1  A: 

Using lambda expressions:

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];
    }
}

Essentially:

  • Sort into a new list in order of date
  • Select the first and last elements of that list

UPDATE: Thinking about it, I'm not sure that this is the way to do it if you care at all about performance, as sorting the entire list will result in many more comparisons than just scanning for the highest / lowest values.

Kragen
+1  A: 

I'd just make two properties Min,Max, assign them the value of the first item you add to the array, then each time you add a new item just check if its DateTime is less or greater than the Min Max ones.

Its nice and fast and it will be much faster than iterating through the array each time you need to get Min Max.

Ravenheart
+2  A: 

The two in one LINQ query (and one traversal):

arr.Aggregate(
    new { MinDate = DateTime.MaxValue,
          MaxDate = DateTime.MaxValue },
    (accDates, record) => 
        new { MinDate = record.Date < accDates.MinDate 
                        ?  record.Date 
                        : accDates.MinDate,
              MaxDate = accDates.MaxDate < record.Date 
                        ?  record.Date 
                        : accDates.MaxDate });
Johnny Blaze
Very interesting! Could you please look at my next question http://stackoverflow.com/questions/2138391/how-to-rewrite-several-independent-linq-quries-into-single-one-using-aggregate I will be happy if you could answer it and I could accept it.
abatishchev