tags:

views:

39

answers:

2

Here is my example:

class test{
    public DateTime dt;
    public double value;
    public int id;
}

i have:

IEnumerable<Test> TestList;

I want select rows from it, with group by id, with max(dt).

my query:

var q = from p in TestList
        group p by p.id
        into g
        select new { id = g.Key, dt = g.Max(w => w.dt) }); 

In result i have anonyoumus class with {id_param,dt}, but i want to have field "value" too, like {id,dt,value},how can i do it?

A: 

You have to group by all fields that are not aggregated. So value needs to be summed up or grouped by.

Try:

        var result = TestList
            .GroupBy(t => t.id)
            .Select(g => new { id = g.Key, g.OrderByDescending(c => c.dt).First().dt, g.OrderByDescending(c => c.dt).First().value });
danijels
i dont want to aggregate value, i need it as it is. maybe i need to use join?
eba
well, if you are grouping by ID, that tells me there are more than one item with the same id (smells fishy), and if there are more than one, than you either have to aggregate the values or group by value as well.
danijels
lol, beacuse of many datetimes there are same ids, but what i want, is to select distinct ids, with max time, with their real values
eba
in tsql i could do it by join, but in linq i dont know how to use join for this problem
eba
I've added a suggestion in the reply
danijels
Suggestion: add a `let` so you only need to do the `OrderBy` once.
Richard
A: 

Based on comments and the question, you want: for each distinct id, the instance with the maximum dt.

I would add a help method: MaxBy which allows a whole object to be selected based on the value of a function1:

public static T MaxBy<T,TValue>(this IEnumerable<T> input, Func<T,TValue> projector)
                                where TValue : IComparable<TValue> {
  T found = default(T);
  TValue max = default(TValue);
  foreach (T t in input) {
    TValue p = projector(t);
    if (max.CompareTo(p) > 0) {
      found = t;
      max = p;
    }
  }
  return found;
}

And then the query becomes:

var q = from p in TestList
        group p by p.id into g
        select g.MaxBy(w => w.dt);

NB. this implementation of MaxBy will only work for objects where the value of the member being compared is greater than its type's default value (e.g. for int: greater than zero). A better implementation of MaxBy would use the enumerator manually and initialise both found and max variables directly from the first element of the input.


1 if you are using The Reactive Extensions (Rx) this is included in the System.Interactive assembly.

Richard
its has error in the line max.CompareTo(p>0)
eba
and where i have to add that method? sry for such questions
eba
@eba: Corrected missing `)`. Add this to a static class in the assembly.
Richard
so, the way of danijels, seems to be easier
eba