我有一个通用列表
简化示例var list = new List<string>()
{
"lorem1.doc",
"lorem2.docx",
"lorem3.ppt",
"lorem4.pptx",
"lorem5.doc",
"lorem6.doc",
};
我想做的是根据外部列表排序
对这些项进行排序在示例var sortList = new[] { "pptx", "ppt", "docx", "doc" };
// Or
var sortList = new List<string>() { "pptx", "ppt", "docx", "doc" };
linq有什么内置的东西可以帮助我实现这个目标吗?还是我必须走每一条路?
对于Enumerable.OrderBy
,您可以使用IndexOf
:
var sorted = list.OrderBy(s => sortList.IndexOf(Path.GetExtension(s)));
因此扩展在sortList
中的索引决定了在其他列表中的优先级。未知扩展具有最高优先级,因为它们的索引为-1。
但是你需要在扩展中添加一个点来让它工作:
var sortList = new List<string>() { ".pptx", ".ppt", ".docx", ".doc" };
如果这不是一个选项,你必须摆弄Substring
或Remove
,例如:
var sorted = list.OrderBy(s => sortList.IndexOf(Path.GetExtension(s).Remove(0,1)));
即使某些文件名没有扩展名,这个解决方案也可以工作:
var sortList = new List<string>() { "pptx", "ppt", "docx", "doc" };
var list = new List<string>()
{
"lorem1.doc",
"lorem2.docx",
"lorem3.ppt",
"lorem4.pptx",
"lorem5.doc",
"lorem6.doc",
};
var result =
list.OrderBy(f => sortList.IndexOf(Path.GetExtension(f).Replace(".","")));
您可以尝试使用Array.IndexOf()方法:
var sortedList = list.OrderBy(i => sortList.IndexOf(System.IO.Path.GetExtension(i))).ToList();
sortDicionary
会更有效率:
var sortDictionary = new Dictionary<string, int> {
{ ".pptx", 0 },
{ ".ppt" , 1 },
{ ".docx", 2 },
{ ".doc" , 3 } };
var sortedList = list.OrderBy(i => {
var s = Path.GetExtension(i);
int rank;
if (sortDictionary.TryGetValue(s, out rank))
return rank;
return int.MaxValue; // for unknown at end, or -1 for at start
});
这样查找的是O(1)
而不是O(# of extensions)
。
同样,如果您有大量的文件名和少量的扩展名,使用
可能会更快。var sortedList = list
.GroupBy(p => Path.GetExtension(p))
.OrderBy(g => {
int rank;
if (sortDictionary.TryGetValue(g.Key, out rank))
return rank;
return int.MaxValue; // for unknown at end, or -1 for at start
})
.SelectMany(g => g);
这意味着排序根据输入中不同扩展的数量进行缩放,而不是根据输入中的项数进行缩放。
这也允许你给两个扩展相同的优先级。
这里有另一种不使用OrderBy
的方法:
var res =
sortList.SelectMany(x => list.Where(f => Path.GetExtension(f).EndsWith(x)));
请注意,这种方法的复杂性是O(n * m)
与n = sortList.Count
和m list.Count
。
OrderBy
接近最坏情况的复杂性是O(n * m * log m)
,但可能在一般情况下它会更快(因为IndexOf
并不总是导致O(n)
)。然而,对于小n
和m
,您不会注意到任何差异。
对于大列表,最快的方法(复杂度O(n+m)
)是构造一个临时查找,即:
var lookup = list.ToLookup(x => Path.GetExtension(x).Remove(0,1));
var res = sortList.Where(x => lookup.Contains(x)).SelectMany(x => lookup[x]);