如何按类型订购列表?

时间:2012-08-25 20:12:01

标签: c# linq algorithm list extension-methods

想象一下,您有一个名为List<Foo>的列表。

Foo是一个抽象类,因此可以是FooAFooBFooCFooD。我希望List<T>有一个扩展名,你可以按类型顺序订购这些元素。

例如,如果我有9个元素。

FooA, FooA, FooB, FooD, FooC, FooC, FooA, FooB, FooA

按顺序排序将是。

FooA, FooB, FooC, FooD, FooA, FooB, FooC, FooA, FooA

我正在尝试按照您指定的顺序对该函数进行排序,在本例中,IE,它是:

new[] { typeof(FooA), typeof(FooB), typeof(FooC), typeof(FooD) }

我试图创建这个扩展,但我什么都没得到。你能帮一下吗?我猜我可以用LINQ完成它。

3 个答案:

答案 0 :(得分:6)

您可以按类型对项目进行分组,按类型对组进行排序并交错组:

var groups = items.GroupBy(x => x.GetType())
                  .OrderBy(g => orderedTypes.IndexOf(g.Key))
                  .ToList();

var result = groups.First().Interleave(groups.Skip(1).ToArray());

使用Interleave method from EvenMoreLINQ

foreach (var item in result)
{
    Console.WriteLine(item.GetType());
}

输出:

FooA
FooB
FooC
FooD
FooA
FooB
FooC
FooA
FooA

答案 1 :(得分:1)

对类型进行分组,然后遍历项目,每次添加一组。类似的东西:

var groups =
  collection.GroupBy(x => x.GetType())
  .ToDictionary(g => g.Key, g => g.ToList());

List<Foo> result = new List<Foo>();
int max = groups.Values.Max(n => n.Count);
for (int i = 0; i < max; i++) {
  foreach (Type  t in sortArray) {
    if (groups[t].Count > i) {
      result.Add(groups[t][i]);
    }
  }
}

答案 2 :(得分:0)

list是要排序的元素的集合 pattern是按特定顺序排列的元素集合 result是根据list排序的pattern元素的集合。

var list = new List<Foo> { new FooA(), new FooB(), new FooC(), new FooA(), new FooC(), new FooA(), new FooD() };
var pattern = new Foo[] { new FooB(), new FooC(), new FooD(), new FooA() };

var result = list.OrderBy(p => p, new MyFooComparer(pattern));

有一个类MyFooComparer实现了接口IComparer<>
比较基于Foo集合中每个pattern的位置。 pattern元素不得重复,且必须包含所有类型的Foo(至少list中使用的那些)。
我使用{{ 1}}存储模式顺序,因为它具有O(1)复杂性。

Dictionary<>

致电:

public class MyFooComparer : IComparer<Foo>
{
    private readonly Dictionary<Type, int> _pattern;
    public MyFooComparer(IEnumerable<Foo> pattern)
    {
        _pattern = new Dictionary<Type, int>();
        int i = 0;
        foreach (var foo in pattern)
        {
            _pattern.Add(foo.GetType(), i);
            i++;
        }
    }

    public int Compare(Foo x, Foo y)
    {
        var xVal = _pattern[x.GetType()];
        var yVal = _pattern[y.GetType()];
        return xVal.CompareTo(yVal);
    }
}

根据 foreach (var foo in result) { Console.WriteLine(foo.GetType().Name); } ,您将获得:

pattern

修改

FooB FooC FooC FooD FooA FooA FooA 的扩展名:

List<Foo>