简体   繁体   中英

linq query to find the objects that are the maximum and the minimum

I have a list of DailyValue structs called stockValues. I need to find the object with the maximum and the minimum High value.

(Here is the struct for reference's sake)

struct DailyValues
{
        public DateTime Date { get; private set; }
        public decimal Open { get; private set; }
        public decimal High { get; private set; }
        public decimal Low { get; private set; }
        public decimal Close { get; private set; }
        public decimal Volume { get; private set; }
        public decimal AdjClose { get; private set; }
}

I've tried a couple various things,

var mx = stockValues.Max(sv => sv.High);

Only gives me the correct maximum value, but it does not let me access the whole object and it's members (what I want is the actual value AND the date it occurred). So I attempted this:

var stuff = from s in stockValues
                        group s by s.Date into g
                        where g.Max(x => x.High)
                        select g;

However, this just underlines g.Max(..) and states that the compiler cannot implicitly convert a decimal into a boolean. While I am not new to C#, I have no experience with Linq and cannot seem to wrap my mind around it quite correctly (I'm sure this is very simple, I'm just not doing it right). Can anyone steer me correctly?

As always, thanks to all in advance!

You could use MaxBy and MinBy methods from moreLINQ library.

var max = stockValues.MaxBy(sv => sv.High);
var min = stockValues.MinBy(sv => sv.High);

They return entire object instead of just the max/min value of property you're trying to sort by.

If you'd like to stay with standard set of LINQ methods, you can do following:

var max = stockValues.OrderByDescending(sv => sv.High).First();
var min = stockValues.OrderBy(sv => sv.High).First();

Or to perform ordering just once:

var ordered = stockValues.OrderBy(sv => sv.High).ToList();
var max = ordered.Last();
var min = ordered.First();

I think you have to perform in 2 steps:

var mx = stockValues.Max(sv => sv.High);
var result = stockValues.Where(sv=>sv.High == mx);

You can use FirstOrDefault instead of Where if you just want 1 item.

UPDATE

If you just want 1 item, I think using Aggregate is the best choice :

var result = stockValues.Aggregate((a, b) => b.High > a.High ? b : a);

To get multi-items (of the same max High ), the code can be like this:

var results = stockValues.Aggregate(new List<DailyValues>(), (a,b)=>{
                                    if (a.Count == 0) a.Add(b);
                                    else if (b.High >= a[0].High){
                                      if(b.High > a[0].High) a.Clear();
                                      a.Add(b);
                                    }                
                                    return a;
                                 });

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM