serene
serene

Reputation: 685

Group a sorted list without affecting the sorting in linq

I have list of objects. I need sorting by a property and then group the result by a set of other properties, but doing it simply changes the ordering and maintains the group first. i need separation of group if needed while maintaining sorting. I tried two ways

  1. Simple Ordering and Grouping

model.OrderBy(o => o.OrderKey).GroupBy(o=> new {o.Key1, o.Key2})

  1. Order as Ordered List (PLINQ) then Group

model.OrderBy(o => o.OrderKey).AsParallel().AsOrdered().GroupBy(o=> new {o.Key1, o.Key2})

My Input would be like

OrderKey Key1 Key2
a        1    2
b        1    2
c        1    3
d        1    2

I expect the output to be like

[
  [a, 1, 2],
  [b, 1, 2]
],
[
 [c, 1, 3]
],
[
 [d, 1, 2]
]

Upvotes: 3

Views: 1322

Answers (1)

Kjartan
Kjartan

Reputation: 19151

This can be solved using the index of each item, and adding some logic to compare to the previous item (unless index is 0):

// Example data
var list = new List<dynamic>{
            new {orderKey = "a", key1 = 1, key2 = 2},
            new {orderKey = "b", key1 = 1, key2 = 2},
            new {orderKey = "c", key1 = 1, key2 = 3},
            new {orderKey = "d", key1 = 1, key2 = 2}
    };

var groupNr = 0; // initial group

var sorted = 
        list
            .OrderBy(i => i.orderKey)
            // Create a new item for each, adding a calculated groupNr:
            .Select((i, nr) => 
                       new { 
                            i.orderKey, 
                            i.key1, 
                            i.key2, 
                            groupNr = (nr == 0 // check if first group
                                           ? 0 // first groupNr must be 0
                                           : (i.key1 == list[nr-1].key1 
                                                && i.key2 == list[nr-1].key2) 
                                              ? groupNr 
                                              : ++groupNr ) 
        })

     // Now just group by the groupNr we have added:
 .GroupBy(i => i.groupNr);

Testing this in LINQPad gives the following result, from which you should be able to extract what you need:

enter image description here

Upvotes: 2

Related Questions