0

I want to get an object from the list that has minimum price value. I did it following way but not getting the item. I do not want to do ordering.

cOrderItem oItem = this.OrderItems
                .Where(p => p.CategoryID == catID && p.n_IsOfferApplied == false)
                .Min(p => p.OrderItemPrice).FirstOrDefault();
NoviceToDotNet
  • 10,387
  • 36
  • 112
  • 166

4 Answers4

2

you can try order by and fetch first element

cOrderItem oItem = this.OrderItems.
   Where(p => p.CategoryID == catID && p.n_IsOfferApplied == false).
   OrderBy(p => p.OrderItemPrice).FirstOrDefault()

this is kind of work around i dont wnat you to use but as you requested you dont want order by than

 var data = (from r in OrderItems
            where r.CategoryID == catID && r.n_IsOfferApplied == false
                   group r by r.CategoryID into g
                   select new { id = g.Key, data= g.Min(a=>a.OrderItemPrice) }).
                 FirstOrDefault();

 var cat =  from r in OrderItems
            join d in data data on d.id == r.CategoryID
            select r;

Note : solution is not tried by me and not recommended to use

Pranay Rana
  • 175,020
  • 35
  • 237
  • 263
1

You have to match each element against the minimum value that is occuring in the collection.

cOrderItem oItem = this.OrderItems
            .Where(p => 
                       p.CategoryID == catID 
                       && p.n_IsOfferApplied == false

                       //Read as: "where the OrderItemPrice value is equal to the lowest occuring value in this.OrderItems
                       && p.OrderItemPrice == this.OrderItems.Min(q => q.OrderItemPrice))

            .FirstOrDefault();

In case you need multiple items (if they have the same OrderItemPrice), you can do the exact same query, but drop the .FirstorDefault() at the end.

Flater
  • 12,908
  • 4
  • 39
  • 62
0

Min doesn't return the item.It returns an integer or double result etc.If you want the item first get the min value then use it with where clause

var minValue = this.OrderItems.Min(p => p.OrderItemPrice);
cOrderItem oItem = this.OrderItems.Where(p => p.CategoryID == catID 
                                             && p.n_IsOfferApplied == false
                                             &&  p.OrderItemPrice == minValue)
                                    .FirstOrDefault();
Selman Genç
  • 100,147
  • 13
  • 119
  • 184
-1

When you use OrderBy it creates new, ordered copy of source sequence in memory (and enumerates source one more time). If you want to avoid this, you can use MoreLINQ MinBy (available from NuGet)

cOrderItem oItem = OrderItems
                .Where(p => p.CategoryID == catID && !p.n_IsOfferApplied)
                .MinBy(p => p.OrderItemPrice);

NOTE: it will throw exception if there is no matching items, so you can use your own extension to return default value if it is possible that no matches will be found:

    public static T MinBy<T, TKey>(
        this IEnumerable<T> source, Func<T, TKey> selector)
    {
        // throw if source or selector is null
        using (var iterator = source.GetEnumerator())
        {
            if (!iterator.MoveNext())
               return default(T);

            var min = iterator.Current;
            var minKey = selector(min);
            IComparer<TKey> comparer = Comparer<TKey>.Default;

            while (iterator.MoveNext())
            {
                var current = iterator.Current;
                var currentKey = selector(current);
                if (comparer.Compare(currentKey, minKey) < 0)
                {
                    min = current;
                    minKey = currentKey;
                }
            }

            return min;
        }            
    }
Sergey Berezovskiy
  • 232,247
  • 41
  • 429
  • 459
  • Just interesting - what's wrong with this solution? It does not use ordering and it fixes issue with empty sequence in default MinBy implementation – Sergey Berezovskiy Feb 05 '14 at 11:49