【问题标题】:Fastest way to sort a List by two fields, one alphabetical and the other custom?按两个字段对列表进行排序的最快方法,一个按字母顺序排列,另一个按自定义排列?
【发布时间】:2012-02-22 10:04:48
【问题描述】:

假设我有一个List<Pet>,每个宠物都有一个Pet.NamePet.Type 字段。

例如:

姓名:鲍勃类型:鱼

名称:雷克斯类型:狗

姓名:阿尔夫类型:狗

名称:蓬松类型:猫

名称:阿波罗类型:鱼

名称:芒果类型:马

现在我想首先按名称按字母顺序排序,然后按类型(非字母)排序。

第二个排序(类型)不是按字母顺序,而是特定/自定义。

例如,假设顺序应始终为:鱼、马、狗、猫。

因此,从上述数据中正确排序的列表将如下所示:

阿波罗,鱼

阿尔夫,狗

鲍勃,鱼

毛茸茸的猫

芒果,马

雷克斯,狗

或者说得更清楚:

A,鱼

A,马

A,狗

一只猫

B,鱼

B,马

B,狗

B,猫

C,鱼

C,马

C,狗

C,猫

这意味着有时 Cat 可能会出现在 Dog 之前,但前提是存在名称为“A”的 Cat 而没有名称为“A”的 Dog...明白了吗?

所以它是按字母顺序排序的,但是在每个字母组中,它会根据第二个字段以自定义方式排序。

那么以这种方式对该列表进行排序的最快方法是什么?

【问题讨论】:

  • 我没有答案,但我只是想知道:“最快的方式”是指你写得最快还是运行时最快?
  • @BrianSnow Runtime...虽然这里有一个不归路,但我不喜欢例如 500 行的解决方案。
  • 你是按名字的第一个字母分组,然后按类型排序吗?如果排序是纯 alpha(name) 后跟类型,我们应该只在名称相同的情况下按类型排序,还是我看错了?
  • @AlanT 这可能确实是一种更好的措辞方式......

标签: c# list sorting


【解决方案1】:

怎么样:

string[] orderedTypes = { "Fish", "Horses", "Dogs", "Cats" };

var orderedPets = sourcePets.OrderBy(pet => pet.Name)
                            .ThenBy(pet => Array.IndexOf(orderedTypes, pet.Type));

现在这样的效率并不高,因为它需要多次线性搜索 orderedTypesstring 数组来执行二级排序,但只有 4 种宠物,这应该不会太糟糕。

如果您真的很担心这一点(假设还有更多的宠物类型),您可以先创建一个查找:

var orderByType = new[] { "Fish", "Horses", "Dogs", "Cats" }
                  .Select(Tuple.Create<string, int>)
                  .ToDictionary(tuple => tuple.Item1, tuple => tuple.Item2);

var orderedPets = sourcePets.OrderBy(pet => pet.Name)
                            .ThenBy(pet => orderByType[pet.Type]);

如果你有这样的枚举而不是字符串:

 public enum AnimalType
 {
     Fish, Horses, Dogs, Cats
 }

那么操作就这么简单:

var orderedPets = sourcePets.OrderBy(pet => pet.Name)
                            .ThenBy(pet => pet.Type);

【讨论】:

  • 这实际上对于我正在尝试做的事情来说已经足够了,我会试一试,如果效果很好,一定要回来选择这个作为答案。
【解决方案2】:

OrderBy() 将使用自定义比较器执行此操作。

public class Pet {
    public string Name { get; set; }
    public string Type { get; set; }
}

[TestMethod]
public void TestMethod1() {

    var pets = new List<Pet>() {
            new Pet{Name= "Bob", Type= "Fish"},
            new Pet{Name= "Rex", Type= "Dog"},
            new Pet{Name= "Alf", Type= "Dog"},
            new Pet{Name= "Fluffy", Type= "Cat"},
            new Pet{Name= "Apollo", Type= "Fish"},
            new Pet{Name= "Mango", Type= "Horse"}
    };

    var expected = new List<string>() {
            "Apollo, Fish",
            "Alf, Dog",
            "Bob, Fish",
            "Fluffy, Cat",
            "Mango, Horse",
            "Rex, Dog",
    };


    var sortedPets = pets.OrderBy(pt => pt, new PetEqualityComparer()).Select(pt => string.Format("{0}, {1}", pt.Name, pt.Type));

    Assert.IsTrue(expected.SequenceEqual(sortedPets));

}

public class PetEqualityComparer : IComparer<Pet> {

    readonly static string[] PetTypes = new [] { "Fish", "Horse", "Dog", "Cat" };

    public int Compare(Pet x, Pet y) {

        var xFirst = string.IsNullOrEmpty(x.Name) ? 'A' - 1 : x.Name[0];
        var yFirst = string.IsNullOrEmpty(y.Name) ? 'A' - 1 : y.Name[0];

        if (xFirst != yFirst) {
                return xFirst.CompareTo(yFirst);
        }
        return Array.IndexOf(PetTypes,x.Type).CompareTo(Array.IndexOf(PetTypes, y.Type));                
    }

}

如果宠物类型顺序可以改变,那么它可以作为构造参数传递给比较器,而不是硬编码。

HTH,
艾伦。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-01-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-07-09
    相关资源
    最近更新 更多