按两个字段(一个按字母顺序,另一个按自定义)对列表进行排序的最快方法
本文关键字:列表 方法 自定义 排序 顺序 字段 两个 一个 另一个 | 更新日期: 2023-09-27 18:22:05
假设我有一个List<Pet>
,每个Pet有一个Pet.Name
和Pet.Type
字段。
例如:
名称:Bob类型:Fish
名称:雷克斯类型:狗
名称:Alf类型:狗
名称:蓬松型:Cat
名称:Apollo型号:Fish
名称:芒果类型:马
现在,我想先按名称的字母顺序进行排序,然后按类型(非alpha)进行排序。
第二种排序(Type)不是按字母顺序排列的,而是特定的/自定义的。
例如,假设顺序应该始终是:鱼、马、狗、猫。
因此,从上述数据中正确排序的列表如下所示:
Apollo,Fish
Alf,狗
Bob,Fish
蓬松,Cat
芒果、马
雷克斯,狗
或者更清楚地说:
A、 鱼类
A、 Horse
A、 狗
A、 Cat
B、 鱼类
B、 Horse
B、 狗
B、 Cat
C、 鱼类
C、 Horse
C、 狗
C、 Cat
这意味着有时猫可以出现在狗之前,但前提是有"A"名字的猫,但没有"A"名称的狗。。。明白了吗?
所以它是按字母顺序排序的,但在每个字母组中,它都是根据第二个字段按自定义方式排序的。
那么,以这种方式对列表进行排序的最快方法是什么呢?
怎么样:
string[] orderedTypes = { "Fish", "Horses", "Dogs", "Cats" };
var orderedPets = sourcePets.OrderBy(pet => pet.Name)
.ThenBy(pet => Array.IndexOf(orderedTypes, pet.Type));
现在,它的效率不如预期,因为它需要多次线性搜索orderedTypes
字符串数组来执行二级排序,但只有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);
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));
}
}
如果Pet-Type顺序可以更改,那么它可以作为构造时的参数传递到比较器中,而不是硬编码。
HTH,
阿兰。