有一个Package项目列表按排序GUID,但我需要按如下顺序排序
KK %, AB, AB art, DD %, FV, ER, PP and WW
我已经实现如下,但我想知道有更好的方法吗?
List<PackageType> list = new List<PackageType> (8);
foreach (var a in mail.Package)
{
if (a.Name == "KK %")
list[0] = a;
else if (a.Name == "AB art")
list[1] = a;
else if (a.Name == "AB")
list[2] = a;
else if (a.Name == "DD %")
list[3] = a;
else if (a.Name == "FV")
list[4] = a;
else if (a.Name == "ER")
list[5] = a;
else if (a.Name == "PP")
list[6] = a;
else if (a.Name == "WW")
list[7] = a;
}
Run Code Online (Sandbox Code Playgroud)
您可以将其缩减为两行(一行用于数组定义,另一行用于排序):
var PackageOrder = new[] { "KK %", "AB", "AB art", "DD %", "FV", "ER", "PP", "WW"};
//...
var list = mail.Package.OrderBy(p => Array.IndexOf(PackageOrder, p.Name)).ToList();
Run Code Online (Sandbox Code Playgroud)
但我们还可以做得更好。
到目前为止的代码要么需要在引用数组中进行多次 O(n) 查找,要么切换到 a Dictionary<string,int>,对于1可能与任务不成比例的值,每次查找都是 O(1) 。在排序操作过程中,每个包项可能需要多次这样的查找,这意味着这可能比您想要的效率低。
我们可以这样解决:
private static string[] Names = new[] { "KK", "AB", "BC", "DD", "FV", "ER", "PP", "WW" };
//...
var list = mail.Package.
Select(p => new {Package = p, Index = Array.IndexOf(Names, p.Name)}).
OrderBy(p => p.Index).
Select(p => p.Package).ToList();
Run Code Online (Sandbox Code Playgroud)
这保证在排序过程中每个包只查找一次。这个想法是首先创建一个包含索引的原始数据的投影,然后按索引排序,最后投影回原始数据。现在唯一的问题是是使用数组还是字典,这主要取决于引用数组的大小(对于这个大小数据粘数组,对于超过15个项目,切换到字典;但它取决于GetHashCode()您类型的性能)。
当然,还有 YAGNI 需要考虑。对于大集合,这通常会好得多,但对于小数据,它可能不值得,或者如果数据碰巧以某种幸运的方式排序,它会使事情变得更慢。如果您受到内存压力的限制而不是 CPU 时间(在 Web 服务器上很常见),它也会使事情变慢。但从一般意义上讲,这是朝着正确方向迈出的一步。
最后,我质疑List<T>这里是否需要实际。只需将声明更改为var并删除.ToList()末尾的 。等待电话ToList()或ToArray()直到您绝对需要它,IEnumerable<T>然后再使用简单的方法。这通常可以大大提高性能。
在这种情况下(作为参考,我稍后添加了这一段),看起来您总共只有 8 个项目,这意味着额外的代码并没有真正为您节省任何东西。考虑到这一点,我只会坚持使用此答案顶部的两行解决方案(当性能无关紧要时,请使用更少或更简单的代码)。
// List<PackageType> list = ...;
var names = new[] { "KK", "AB", "BC", "DD", "FV", "ER", "PP", "WW" };
var sortedList = list.OrderBy(packageType => Array.IndexOf(names, packageType.Name));
Run Code Online (Sandbox Code Playgroud)
这是上面的更长版本,它更详细地解释了正在发生的事情:
// this array contains all recognized keys in the desired order;
private static string[] Names = new[] { "KK", "AB", "BC", "DD", "FV", "ER", "PP", "WW" };
// this helper method will return the index of a `PackageType`'s `Name`
// in the above array, and thus a key by which you can sort `PackageType`s.
static int GetSortingKey(PackageType packageType)
{
var sortingKey = Array.IndexOf(Names, packageType.Name);
if (sortingKey == -1) throw new KeyNotFoundException();
return sortingKey;
}
// this is how you could then sort your `PackageType` objects:
// List<PackageType> list = ...;
IEnumerable<PackageType> sortedList = list.OrderBy(GetSortingKey);
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
927 次 |
| 最近记录: |