按外部排序顺序对通用列表进行排序

时间:2013-01-09 11:41:31

标签: c# linq

我有一个通用列表

简化示例

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内置了什么东西可以帮助我实现这个目标,还是我必须采用foreach方式?

5 个答案:

答案 0 :(得分:8)

使用此列表,您可以IndexOf使用Enumerable.OrderBy

var sorted = list.OrderBy(s => sortList.IndexOf(Path.GetExtension(s)));

因此sortList中的扩展名索引确定了另一个列表中的优先级。未知扩展名具有最高优先级,因为它们的索引为-1。

但是您需要在扩展中添加一个点才能使其正常工作:

var sortList = new List<string>() { ".pptx", ".ppt", ".docx", ".doc" };

如果这不是一个选项,你必须摆弄SubstringRemove,例如:

var sorted = list.OrderBy(s => sortList.IndexOf(Path.GetExtension(s).Remove(0,1)));

答案 1 :(得分:6)

即使某些文件名没有扩展名,此解决方案仍然有效:

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(".","")));

答案 2 :(得分:1)

您可以尝试使用Array.IndexOf()方法:

var sortedList = list.OrderBy(i => sortList.IndexOf(System.IO.Path.GetExtension(i))).ToList();

答案 3 :(得分:1)

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);

这意味着排序按输入中不同扩展的数量而不是输入中的项目数量进行缩放。

这也允许您为两个扩展提供相同的优先级。

答案 4 :(得分:0)

这是另一种不使用OrderBy的方式:

var res = 
sortList.SelectMany(x => list.Where(f => Path.GetExtension(f).EndsWith(x)));

请注意,此方法的复杂性为O(n * m) n = sortList.Countm list.Count

OrderBy方法最坏情况的复杂性是O(n * m * log m),但通常它会更快(因为IndexOf不会始终在O(n)中)。但是,对于小nm,您不会发现任何差异。

对于大型列表,最快的方式(复杂性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]);