2

This is my code

var y = tb.AsEnumerable()
          .GroupBy(r => new { pp1 = r[listView2.Items[0].Text], 
                              pp2 = r[listView2.Items[1].Text] })
          .Select(h => new { c1 = h.Key.pp1, 
                             c2 = h.Key.pp2, 
                             Total = h.Sum(s => s.Field<double>(listView3.Items[0].Text)) });

My problem is that I should GroupBy using listview items which contains the columns names that I will GroupBy But This code can only accept 2 items

Is there any way to GroupBy using a list of string ?

default locale
  • 13,035
  • 13
  • 56
  • 62
Abbes omar
  • 51
  • 4
  • possible duplicate of [Dynamic LINQ Group By Query in ASP.NET MVC](http://stackoverflow.com/questions/2448611/dynamic-linq-group-by-query-in-asp-net-mvc) – default locale Aug 11 '14 at 19:20
  • 1
    @defaultlocale, did you bother to read that answer? – crthompson Aug 11 '14 at 19:21
  • @paqogomez yes, what's wrong with it? The question is still the same: `GroupBy` with list of properties. – default locale Aug 11 '14 at 19:24
  • 1
    @defaultlocale yes, and here he's not grouping on *properties* of the object, rather he's grouping on a static property of the value returned by the indexer when passed each of N different string values. – Servy Aug 11 '14 at 19:47
  • @Servy your answer is really great! I voted it up. Honestly, I didn't even think about using sequence comparison in this context. Anyway, I still believe that question in my first comment is extremely close to this one (and OP might want to take a look on the answers there). – default locale Aug 11 '14 at 19:57
  • Couple more related questions: http://stackoverflow.com/questions/4128195/using-dynamic-linq-for-groupby-on-datatable and http://stackoverflow.com/questions/18059659/how-to-perform-group-by-operation-in-datatable-using-multiple-columns-dynamicall – default locale Aug 11 '14 at 19:59
  • @defaultlocale It's similar, but there isn't any particularly practical way to use that solution to solve that problem. That solution isn't particularly generalized, and is rather tied to several implementation-specific limitations that don't apply here. – Servy Aug 11 '14 at 20:00

1 Answers1

2

You can use the following class to create a comparer that can compare sequences of items based on the values in those sequences, rather than based on the reference to the sequence:

public class SequenceComparer<T> : IEqualityComparer<IEnumerable<T>>
{
    private IEqualityComparer<T> comparer;
    public SequenceComparer(IEqualityComparer<T> comparer = null)
    {
        comparer = comparer ?? EqualityComparer<T>.Default;
    }
    public bool Equals(IEnumerable<T> x, IEnumerable<T> y)
    {
        return x.SequenceEqual(y, comparer);
    }

    public int GetHashCode(IEnumerable<T> sequence)
    {
        unchecked
        {
            int hash = 19;
            foreach (var item in sequence)
                hash = hash * 79 + comparer.GetHashCode(item);
            return hash;
        }
    }
}

Once we have this we can transform your grouping selector so that it projects out a sequence of the items you are interested in, since it's not known at compile time. The Select selector is largely unchanged.

var y = tb.AsEnumerable()
    .GroupBy(row => listView2.Items.Cast<ListViewItem>()
        .Select(item => row[item.Text]), new SequenceComparer<object>())
    .Select(group => new
    {
        Values = group.Key,
        Total = group.Sum(s => s.Field<double>(listView3.Items[0].Text)),
    });
Servy
  • 202,030
  • 26
  • 332
  • 449