【问题标题】:How to use LINQ to order a file name by a substring using a condition?如何使用 LINQ 使用条件通过子字符串对文件名进行排序?
【发布时间】:2019-01-08 13:59:23
【问题描述】:

我试图在我的网站上列出的文件夹及其子文件夹中有一些 Excel (.xlsx) 文件。文件名格式如下:

2018_MyData_Day.xlsx
2018_MyData_Month.xlsx
2018_MyData_Year.xlsx
2019_MyData_Day.xlsx
2019_MyData_Month.xlsx
2019_MyData_Year.xlsx

注意:DayMonthYear 是文本,不是实际数字日、月或年的占位符(以防误导)。 p>

我需要以降序文件名显示这些文件名,但按特定顺序按YearDayMonth 分组。因此,使用上面的列表,输出应该是:

2019_MyData_Year.xlsx
2018_MyData_Year.xlsx

2019_MyData_Day.xlsx
2018_MyData_Day.xlsx

2019_MyData_Month.xlsx
2018_MyData_Month.xlsx

我使用以下按年份和DayMonthYear 子字符串对文件名进行排序,但子字符串的排序不正确:

var fileGroup = (
    from file in Directory.EnumerateFiles(myPath, searchPattern: "*.xlsx", searchOption: SearchOption.AllDirectories)
    let fileName = Path.GetFileName(file)
    orderby fileName descending
    select fileName
).OrderBy(f => f.Substring(f.LastIndexOf("_")))

我确定我需要一个条件,因为所需的顺序是自定义的,但我不确定如何实现它。

这是否可能或有更好的方法来实现我想要的输出?

谢谢!

【问题讨论】:

  • 首先你应该像你写的那样对你的“字符串”进行分组,并且你的代码没有对你的集合进行分组。
  • 所以 _year、_month 和 _day 是文件名中的固定后缀(我不确定我是否正确)?如果是这样,您可以将文件分成三个列表并排序这些 ==> filelist.Where(i => i.EndsWith("_year").OrderByDescending(i => i);
  • @MichałK。 - 我认为这就是我遇到的麻烦。我不确定如何按特定顺序对YearDayMonth 进行分组。
  • @Martin - 是的,“_Year”、“_Day”和“_Month”是固定的文本后缀。文件名与问题中显示的完全相同,而不是像“2019_MyData_2012.xlsx”这样的名称。对于您的建议,我将不得不写三个单独的陈述,对吗?如果可能的话,我希望在一份声明中做到这一点。
  • @user2063351 然后看看我的回答:)

标签: c# .net linq lambda linq-to-sql


【解决方案1】:

为什么不使用 Select 将文件名投影到两个属性的位置:

  • FileYear:2018、2019,直到第一个下划线之前的所有内容
  • FilePeriod:一个 int,其中 (0) = 年,(1) = 日,(2) = 月,第二个下划线之后的部分

.

var underscore = new char[] {'_'};
var orderedFiles = originalFiles.Select(fileName =>
{
    // TODO: decide what to do if filename incorrect format
    var splitFileName = fileName.Split(underscore);

    int filePeriod;
    switch (splitFileName[2])
    {
        case "Year":
            filePeriod = 0;
            break;
        case "Day":
            filePeriod = 1;
            break;
        case "Month":
            filePeriod = 2;
            break;
        default:
            filePeriod = 3;
            break;
    }

    return new
    {
        FileYear = Int32.Parse(splitFileName[0]),
        FilePeriod = filePeriod,
        OriginalFileName = fileName,
    };
})

// sort:
.OrderBy(splitFile => splitFile.FileYear)
.ThenBy(splitFile => splitFile.FilePeriod)

// back to original filename
.Select(splitFile => splitFile.OriginalFileName);

【讨论】:

    【解决方案2】:

    您可以按如下方式使用 LINQ。

    var list = new []{
        "2018_MyData_Day.xlsx",
        "2018_MyData_Month.xlsx",
        "2018_MyData_Year.xlsx",
        "2019_MyData_Day.xlsx",
        "2019_MyData_Month.xlsx",
        "2019_MyData_Year.xlsx"
         };
    
        var result = list.GroupBy(x=> new { Type= x.Split(new[]{"_"},StringSplitOptions.RemoveEmptyEntries)[2]})
                         .Select(x=> new {Key = x.Key, FullName = x.OrderBy(c => c)});
    

    【讨论】:

      【解决方案3】:

      您可以使用一些 let 轻松做到这一点:

      var fileGroup = (from f in Directory.GetFiles(myPath, "201*.xlsx")
                      let fName = Path.GetFileNameWithoutExtension(f)
                      let ymd = fName.Substring("2000_MyData_".Length).ToLower()
                       let fOrder = (ymd == "year" ? 0 : ymd == "day" ? 1 : 2)
                       select new {f, year=int.Parse(fName.Substring(0,4)), o=fOrder})
                      .OrderBy(g => g.o)
                      .ThenByDescending(g => g.year)
                      .Select(g => g.f);
      

      【讨论】:

        【解决方案4】:
         var fileGroup = (from file in Directory.EnumerateFiles(myPath, searchPattern: "*.xlsx", searchOption: SearchOption.AllDirectories)
                    let fileName = Path.GetFileName(file)
                    select fileName)
                    .GroupBy(f => f.Substring(f.LastIndexOf("_") + 1))
                    .Select(x => x.OrderBy(y => y));
        

        我认为这可能会解决您的问题。

        【讨论】:

          【解决方案5】:
          IEnumerable<string> files = Directory.EnumerateFiles(myPath, searchPattern: "*.xlsx", searchOption: SearchOption.AllDirectories).Select(x => Path.GetFileName(x));
          
          Regex reg = new Regex(".*_(?<dmy>Day|Month|Year)\\.xlsx");
          var groups = files.GroupBy(x => reg.Match(x).Groups["dmy"].Value);
          StringBuilder builder = new StringBuilder();
          foreach (var g in groups.OrderBy(x => x.Key == "Year" ? 0 : x.Key == "Day" ? 1 : 2))
          {
              builder.AppendLine();
              foreach(var f in g.OrderByDescending(x => x))
              {
                  builder.AppendLine(f);
              }
          }
          

          【讨论】:

            【解决方案6】:

            您可以尝试将您的代码更改为:

            var fileGroup = (
            from file in Directory.EnumerateFiles(myPath, searchPattern: "*.xlsx", searchOption: SearchOption.AllDirectories)
            let fileName = Path.GetFileName(file)
            let fileParts = fileName.Split('.')[0].Split('_')
            orderby fileParts[2] descending, fileParts[0] descending
            select fileName
            )
            

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 2011-03-10
              • 1970-01-01
              • 2021-11-09
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多