开发者

LINQ - group specific types of classes

开发者 https://www.devze.com 2022-12-30 21:15 出处:网络
This question is similar to LINQ group one type of item but handled in a more generic way. I have a List that has various derived classes. I may have something like this:

This question is similar to LINQ group one type of item but handled in a more generic way.

I have a List that has various derived classes. I may have something like this:

List<BaseClass> list = new List<BaseClass>() {
  new Class1(1),
  new Class2(1),
  new Class1(2),
  new Class3(1),
  new Class2(2),
  new Class4(1),
  new Class3(2)
};

I am trying to use LINQ to semi-sort the list so that the natural order is maintained EXCEPT for certain classes which have base.GroupThisType == true. All classes with GroupThisType should be grouped together at the place that the first class of the same type occurs. Here is what the output should be like:

List<BaseClass> list = new List<BaseClass>() {
  new Class1(1),
  new Class1(2),
  new Class2(1),
  new Class3(1),
  new Class3(2)
  new Class2(2),
  new Class4(1),
};

Edit: Oops, forgot to say this result 开发者_开发问答is assuming (Class1 and Class3).GroupThisType == true


Like this:

list = list.Select((o, i) => new { Index = i * 10000, Value = o })
           .GroupBy(q => q.GetType())
           .SelectMany(g => {
               if (g.First().GroupThisType)
                   return g.Select((q, i) => 
                       new { Index = g.First().Index + i, Value = q.Value }
                   );
               else
                   return g;
           })
           .OrderBy(q => q.Index)
           .Select(q => q.Value)
           .ToList();

The i * 10000 allows up to 10,000 items from a group to be inserted between any two items.

You can replace g.First().GroupThisType with typesToGroup.Contains(g.Key).


Here's a solution using two passes: in the first I build a dictionary of all the ones that should group. In the second I use SelectMany to gather up the elements that don't collate with the collated sequences for the first of any element that does collate.

// Build a dictionary of the items that group
var onesToGroup = list.Where(x => x.GroupThisClass)
                            .GroupBy(x => x.GetType())
                            .ToDictionary(x => x.Key, x => x.AsEnumerable());

var results = list.SelectMany(x => x.GroupThisClass ?
                             (onesToGroup[x.GetType()].First() == x ? onesToGroup[x.GetType()] : (new BaseClass[]{}))
                                                : (new []{x}));


The OrderBy LINQ method can accept an IComparer generic interface. You can use this to implement your custom sorting algorithm. I don't know the default ordering can handle what you are trying to do (it would depend on all the rules you need to implement). I assume you're classes aren't actually named Class1, Class2 with the ordering in the type name?

HTH.

0

精彩评论

暂无评论...
验证码 换一张
取 消