1

I have 2 classes like this:

public partial class Product
{
    public ICollection<ProductTerm> ProductTerms { get; set; }
    // More properties here
}

public partial class ProductTerm
{
    public short ID { get; set; }
    public short MinTermDuration { get; set; }
    // More properties here
}

As you will see, Product has a 1 to many relationship with ProductTerm.

I'm trying to return the entire ProductTerm with the Min MinTermDuration. I can get the result I want here but am returning the MinTermDuration - how do I return the whole ProductTerm?

    int GetMinTerm()
    {
        return ProductTerms.Min(t => t.MinTermDuration);
    } 
dotnetnoob
  • 10,783
  • 20
  • 57
  • 103
  • 1
    See [here](http://stackoverflow.com/questions/914109/how-to-use-linq-to-select-object-with-minimum-or-maximum-property-value) – Vlad Dec 18 '14 at 09:52

3 Answers3

7

You can first order your products and then just take the first one on the top.

return ProductTerms.OrderBy(t => t.MinTermDuration).FirstOrDefault();
Vsevolod Goloviznin
  • 12,074
  • 1
  • 49
  • 50
2

You could use OrderBy(...).FirstOrDefault(), as suggested by Vsevolod Goloviznin; however this approach needs to sort the collection, which has a complexity of O(n log n)... The approach suggested by Selman22 is better, but it still enumerates the result twice (which could be an issue if the sequence is an Entity Framework or OData query).

A better option is to use a MinBy extension method that just loops over the collection once and returns the item that has the min value, with a complexity of O(n):

return ProductTerms.MinBy(t => t.MinTermDuration);

You can find such a method in Linq.Extras or in MoreLinq.


EDIT: the above is true if you're working with an in-memory collection (Linq to Objects), not if you're working with a database (using Entity Framework for instance). The DB knows how to find the item with the min value efficiently; using MinBy in this case would fetch all rows to examine them, so it would be very inefficient.

Thomas Levesque
  • 286,951
  • 70
  • 623
  • 758
  • I am using Entity Framework - what would the issue be? – dotnetnoob Dec 18 '14 at 10:00
  • @dotnetnoob, EF queries implement `IEnumerable`, so it should work fine. However, in this case it's better to use the `OrderBy` approach, because the DB can do it efficiently, whereas using `MinBy` would fetch all rows to examine them... – Thomas Levesque Dec 18 '14 at 10:04
  • Ah, I see. This shouldn't be a problem - there are less than 100 products, each with around 5 terms. The data is retrieved .AsNoTracking and cached prior to any property being requested. – dotnetnoob Dec 18 '14 at 10:10
1

Min returns the minimum value, not the item with the value. You can use First to get ProductTerm that has MinTermDuration:

ProductTerm GetMinTerm()
{
    var min = ProductTerms.Min(t => t.MinTermDuration);
    return ProductTerms.First(x => x.MinTermDuration == min);
} 

Another alternative would be using MinBy method, it requires using a thir-party library but more straightforward:

ProductTerm GetMinTerm()
{
    return ProductTerms.MinBy(t => t.MinTermDuration);
} 
Selman Genç
  • 100,147
  • 13
  • 119
  • 184