none
OrderBy after a GroupBy? How can I achieve that? RRS feed

  • Question

  • Hello!

    I have the following query:

    var query = this.ObjectContext.Items
    			.Include("Language")
    			.Include("BaseItem.Level")
    			.Where(p => p.Language.TwoLetterIso.ToLower() == fromLang.ToLower() || p.Language.TwoLetterIso.ToLower() == toLang.ToLower())
    			.GroupBy(p => p.BaseItem);
    

    And I want to do something like that, if possible, directly into the query:

    foreach (var item in query)
    {
    	item = item.OrderBy(p => p.Language.TwoLetterIso);
    }
    

    (this can not work in fact... because it's inside a foreach and I'll also have a casting problem!)

    Now a small explanation with words ;-) -> I have a table with items in different languages (items are always available in minimum 2 languages -> these 2 items are linked with a "BaseItem"). With my actual query, I'm able to get the items in both languages and group them by their BaseItem. The problem is that inside the generated "group" I have un-ordered items (once the first item will be in french and the second in english and sometimes it will be the opposite!)

    I need to have always the french OR the english item in first position!

    Thanks for help!

     

    Wednesday, June 8, 2011 7:18 PM

Answers

  • Works for me:

    var q = "one two three four five six seven eight nine ten"
      .Split(' ')
      .GroupBy(o=>o.Substring(0,1))
      .Select(o=>o.OrderBy(i=>i));
    
    // format as:
    // one | ten,three,two | five,four | seven,six | eight | nine
    string result = string.Join(" | ",
      q.Select(g=>string.Join(",",g.ToArray()))
       .ToArray();
    
    

    This groups all my words together by their first letter (.Substring(0,1)).

    Then it orders each group alphabetically.

    The groups come out in stable order (the order they were discovered), and the items within each group are ordered alphabetically with their natural order (OrderBy(i=>i)).

     

    • Marked as answer by bPlatypus Saturday, June 11, 2011 2:23 PM
    Thursday, June 9, 2011 6:05 PM

All replies

  • Hi,

    The type you're getting in your variable item is of type Grouping<string, Item>, when you call OrderBy on this, it returns a OrdredEnumerable<Item, string>, these are not able to cast between eachother automatically, so you need to store the result of your OrderBy in a another variable. You can then work with it as usual.

    But why not call .OrderBy(p => p.Language.TwoLetterIso) in your actual query? Then your DBMS takes care of the sorting for you, a lot more efficient.

    var query = this.ObjectContext.Items
    			.Include("Language")
    			.Include("BaseItem.Level")
    			.Where(p => p.Language.TwoLetterIso.ToLower() == fromLang.ToLower() || p.Language.TwoLetterIso.ToLower() == toLang.ToLower())
    			.OrderBy(p => p.Language.TwoLetterIso).GroupBy(p => p.BaseItem);
    
    

    Hope this helps!


    --Rune
    Wednesday, June 8, 2011 7:42 PM
  • Can you not simply ...OrderBy(p => p.Language.ToLetterIso).GroupBy(p => p.BaseItem);

    I was under the impression that if you order them first, the GroupBy would be stable with respect to the original ordering.

    I suppose it's worth verifying.  But regardless, if not, then you can do:

       ...GroupBy(...).Select(x=>x.OrderBy(...));

    Wednesday, June 8, 2011 7:43 PM
  • Hi!

    Thanks for answer ;-).

    Just adding the OrderBy(p => p.Language.ToLetterIso).GroupBy(p => p.BaseItem); is not working.

    The other solution you suggest, I didn't find a way to do it :-S. Any help? I tried several things with .Select(...) but nothing works :-(

    Thanks!

    Thursday, June 9, 2011 2:21 PM
  • Works for me:

    var q = "one two three four five six seven eight nine ten"
      .Split(' ')
      .GroupBy(o=>o.Substring(0,1))
      .Select(o=>o.OrderBy(i=>i));
    
    // format as:
    // one | ten,three,two | five,four | seven,six | eight | nine
    string result = string.Join(" | ",
      q.Select(g=>string.Join(",",g.ToArray()))
       .ToArray();
    
    

    This groups all my words together by their first letter (.Substring(0,1)).

    Then it orders each group alphabetically.

    The groups come out in stable order (the order they were discovered), and the items within each group are ordered alphabetically with their natural order (OrderBy(i=>i)).

     

    • Marked as answer by bPlatypus Saturday, June 11, 2011 2:23 PM
    Thursday, June 9, 2011 6:05 PM