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;
}
答案 0 :(得分:7)
// List<PackageType> list = ...;
var names = new[] { "KK", "AB", "BC", "DD", "FV", "ER", "PP", "WW" };
var sortedList = list.OrderBy(packageType => Array.IndexOf(names, packageType.Name));
以上是上述版本的较长版本,可以更详细地解释发生了什么:
// 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);
答案 1 :(得分:3)
@stakx答案的更新版本。嗯,我认为这应该是更好的解决方案,如果这些值是固定的,也可以在其他地方使用。枚举中的每个值都有其int值,通过它可以对它们进行排序。
public enum Names
{
KK, //0
AB, //1
BC, //2
DD, //3
FV, //4
ER, //5
PP, //6
WW //7
}
var packageList = list.OrderBy(p => p.Name);
<强>更新强>
在类
中使用enum示例public class Package
{
public Names Name { get; set; }
}
如果需要获取此枚举的字符串值,则只需使用此
Package package
- 包类变量
package.Name.ToString();
如果需要整个枚举名称列表(枚举键名称),可以使用Enum
类方法:
Enum.GetNames(Type enumType)
返回包含所有已定义的枚举键名称的字符串数组。
Enum.GetNames(typeof(Names))
答案 2 :(得分:3)
你可以将它归结为两行(一行用于数组定义,一行用于排序):
var PackageOrder = new[] { "KK %", "AB", "AB art", "DD %", "FV", "ER", "PP", "WW"};
//...
var list = mail.Package.OrderBy(p => Array.IndexOf(PackageOrder, p.Name)).ToList();
但我们可以做得更好。
到目前为止,代码要么需要对引用数组进行几次O(n)查找,要么切换到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();
这保证了在排序过程中每个包只能进行一次查找。我们的想法是首先创建原始数据的投影,该投影还包括索引,然后按索引排序,最后投影回原始数据。现在唯一的问题是是否使用数组或字典,这主要取决于引用数组的大小(对于这个大小数据棒与数组,超过大约15项,切换到字典;但它取决于你的类型的GetHashCode()
表现。)
当然,YAGNI也需要考虑。对于大型集合,这通常会好得多,但对于小数据而言,它可能不值得,或者如果数据恰好以某种幸运方式排序,则可能会使事情变得更慢。如果您受内存压力的限制比cpu时间(在Web服务器上常见)更受限制,它也会使事情变得更慢。但从一般意义上讲,它是朝着正确方向迈出的一步。
最后,我怀疑这里需要一个实际的List<T>
。只需将声明更改为var
,然后删除最后的.ToList()
即可。等待ToList()
或ToArray()
,直到您完全需要它为止,然后使用简单的IEnumerable<T>
。这通常可以大大提高性能。
在这种情况下(作为参考,我后来添加了这一段),看起来你总共只有8个项目,这意味着额外的代码并没有真正为你节省任何东西。考虑到这一点,我只是坚持在这个答案的顶部使用双线解决方案(当性能不重要时,请使用更少或更简单的代码)。
答案 3 :(得分:2)
替代..(我还没有编译)
var indexPositions = new Dictionary<string, int> {
{ "KK", 0 },
{ "AB", 1 },
{ "BC", 2 },
{ "DD", 3 },
{ "FV", 4 },
{ "ER", 5 },
{ "PP", 6 },
{ "WW", 7 }
}
foreach (var package in mail.Package)
{ // access position
int index;
if (!indexPositions.TryGetValue(a.Name, out index)) {
throw new KeyNotFoundException()
}
list[index] = package;
}
答案 4 :(得分:1)
除了通常的OrderBy
Array.IndexOf
方法外,该列表还可以就地排序:
string[] order = { "KK", "AB", "BC", "DD", "FV", "ER", "PP", "WW" };
list.Sort((a, b) => Array.IndexOf(order, a.Name).CompareTo(Array.IndexOf(order, b.Name)));
更高级O(n)
替代方案:
var lookup = list.ToLookup(x => x.Name);
list = order.SelectMany(x => lookup[x]).ToList();