如何基于LINQ中的类型对集合进行排序

时间:2010-10-06 16:39:56

标签: c# linq .net-3.5

我有这样的集合,

Class Base{}
Class A : Base {}
Class B : Base {}

List<Base> collection = new List<Base>();
collection.Add(new A());
collection.Add(new B());
collection.Add(new A());
collection.Add(new A());
collection.Add(new B());

现在我想根据类型(A / B)对集合进行排序。我怎么能这样做?请帮帮我。

8 个答案:

答案 0 :(得分:8)

您可以使用类型信息本身:

collection.Sort( (a,b) => 
  {
      bool aType = a.GetType() == typeof(A);
      bool bType = b.GetType() == typeof(A);
      return aType.CompareTo(bType);
  });

这适用于您指定的两种类型,但不会超出它们。它允许您明确指定顺序(即:如果您想要“A”之前的“B”元素,您可以使用此技术使其工作)。

如果您需要支持多种类型,并且不需要提前指定排序,您可以执行以下操作:

collection.Sort( (a,b) => a.GetType().FullName.CompareTo(b.GetType().FullName) );

这将处理任意数量的类型(即:C和D子类型),并按其完整类型名称对它们进行排序。

答案 1 :(得分:6)

private static int OrderOnType(Base item)
{
  if(item is A)
    return 0;
  if(item is B)
    return 1;
  return 2;
}

然后从以下选择:

collection.OrderBy(OrderOnType)

collection.Sort((x, y) => OrderOnType(x).CompareTo(OrderOnType(y)));

取决于您是否需要就地排序。如果你真的想要的话,你可以将OrderOnType放入lambda中,但这对我来说似乎更具可读性,我更喜欢在添加时保留lambdas而不是降低可读性。

答案 2 :(得分:4)

collection.OrderBy(i => i.GetType() == typeof(A) ? 0 : 1);

将为您提供包含所有A s然后所有B s

的序列

答案 3 :(得分:1)

确实

collection.Where(entry => entry is A).Concat(collection.Where(entry => entry is B))

做你需要的吗?

答案 4 :(得分:1)

这是订单,因此A将是第一个,B是第二个。

var xx = list.OrderBy(x => x.GetType() == typeof(B)).ToList();

以下控制台项目确认:

class Program
{
    public class X { }
    public class A : X { }
    public class B : X { }
    static void Main()
    {
        List<X> list = new List<X>();
        list.Add(new B());
        list.Add(new A());
        list.Add(new B());
        list.Add(new A());
        list.Add(new A());

        // A.GetType() == typeof(B) will be "0" making the type A go first
        // B.GetType() == typeof(B) will be "1" making the type B go last
        var xx = list.OrderBy(x => x.GetType() == typeof(B)).ToList();

        Console.ReadLine();
    }
}

在这种情况下,我假设您只有AB。如果您有更多类型,则必须创建比较器以返回每种类型的值。你也可以在基类上有一个属性来设置元素的顺序,然后你可以用这个属性对列表进行排序。

答案 5 :(得分:0)

编辑:我认为这就是你想要的:

如果您不介意排序“不合适”并重新分配列表,这应该有效:

collection = collection.GroupBy(item => item.GetType())
                       .SelectMany(g => g)
                       .ToList();

或根据您的需要,例如:

collection = collection.OrderBy(item => item.GetType().FullName)
                       .ToList();

如果必须就地,那么编写自定义比较器和list.Sort可能是最好的选择。


要按类别对项目进行分组,您可以使用GroupBy

var groupedItems = collection.GroupBy(item => item.GetType());

这使用延迟执行。

或者,您可以将'groups'放入如下的数据结构中:

var itemsByTypeLookUp = collection.ToLookup(item => item.GetType());

foreach(A a in itemsByTypeLookUp[typeof(A)])
{
   ...
}

如果您只是寻找某种类型:

var itemsOfTypeA = collection.OfType<A>();

答案 6 :(得分:0)

这样的事对我有用。

> Successfully compiled asm.js code (loaded from cache in 21ms) 

> pre-main prep time: 0 ms

> Cannot enlarge memory arrays. Either (1) compile with -s TOTAL_MEMORY=X with X higher than the current value 33554432, (2) compile with ALLOW_MEMORY_GROWTH which adjusts the size at runtime but prevents some optimizations, or (3) set Module.TOTAL_MEMORY before the program runs.
> uncaught exception: abort() at wa@https://webencoder.libbpg.org/js/bpgdec8.js:19:34
> B@https://webencoder.libbpg.org/js/bpgdec8.js:85:320
> z.b@https://webencoder.libbpg.org/js/bpgdec8.js:11:48
> Z@https://webencoder.libbpg.org/js/bpgdec8.js:53:333
> Vd@https://webencoder.libbpg.org/js/bpgdec8.js:70:1
> fd@https://webencoder.libbpg.org/js/bpgdec8.js:70:1
> sd@https://webencoder.libbpg.org/js/bpgdec8.js:70:1
> Mc@https://webencoder.libbpg.org/js/bpgdec8.js:70:1
> Sc@https://webencoder.libbpg.org/js/bpgdec8.js:70:1
> Tc@https://webencoder.libbpg.org/js/bpgdec8.js:70:1
> _b@https://webencoder.libbpg.org/js/bpgdec8.js:66:1 Kb@https://webencoder.libbpg.org/js/bpgdec8.js:66:1
> Pc@https://webencoder.libbpg.org/js/bpgdec8.js:70:1
> Pd@https://webencoder.libbpg.org/js/bpgdec8.js:70:1
> Kd@https://webencoder.libbpg.org/js/bpgdec8.js:70:1
> @https://webencoder.libbpg.org/js/bpgdec8.js line 15 > eval:1:84
> window.BPGDecoder.prototype.load/d.onload@https://webencoder.libbpg.org/js/bpgdec8.js:88:216 If this abort() is unexpected, build with -s ASSERTIONS=1 which can give more information.

> Cannot enlarge memory arrays. Either (1) compile with -s TOTAL_MEMORY=X with X higher than the current value 33554432, (2) compile with ALLOW_MEMORY_GROWTH which adjusts the size at runtime but prevents some optimizations, or (3) set Module.TOTAL_MEMORY before the program runs.

我的代码:

collection.OrderBy(p => p.GetType().Equals(typeof(B))).ThenBy(p => p.GetType().Equals(typeof(A))).ToList();

答案 7 :(得分:0)

这是稍后的答案,但一些简单的方法可能对其他人有用,并且在我的测试过程中可以实现类似的东西

var orderedList = animalList.OrderBy(x=> x.GetType().Name);

foreach(var animal in orderedList)
{
    System.Console.WriteLine(animal.Name);
}

输出如下:

Ape
Ape
Ape
Ape
Cat
Cat
Cat
Cat
Cat
Dog
Dog
Dog
Dog
Dog

其中的animalList类似于:

animalList = new List<IAnimal>();

和IAnimal接口/实现:

public class Ape : IAnimal 
{
    public string Name => "Ape";
    public AnimalType AnimalType => AnimalType.Ape;
}


public class Dog : IAnimal 
{
    public string Name => "Dog";
    public AnimalType AnimalType => AnimalType.Dog;
}

public class Cat : IAnimal
{
    public string Name => "Cat";
    public AnimalType AnimalType => AnimalType.Cat;
}

public interface IAnimal 
{
     string Name {get;}
     AnimalType AnimalType {get;}
}

此外,诸如指定代表您的课程顺序的枚举类型之类的方法可能会有所帮助。示例:

public enum MyOrderType 
{
    Ape = 1,
    Cat = 2,
    Dog = 3
}

那么就像

一样简单
var orderedList = animalList.OrderBy(x=> x.AnimalType).ToList();
相关问题