Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Sort part of a list in descending order (by date), the other part in ascending order (alphabetically)?

Tags:

c#

linq

I have a control which shows a list of all PDFs in a selected folder. The names of most of these PDFs (for example, meeting minutes) begin with a date. I want these PDFs shown in descending order so that the most recent PDFs are shown at the top.

In the same folder I also have some PDFs whose names do not contain a date (for example, policies). I want these files to be ordered alphabetically.

Here is an example of the kind of list I have and how I want it to be ordered:

  • 2019-01-12 Meeting minutes.pdf
  • 2018-11-19 Meeting agenda.pdf
  • 2018-06-02 Meeting minutes.pdf
  • 2017-12-13 Meeting agenda.pdf
  • 2017-04-27 Meeting minutes.pdf
  • Privacy policy.pdf
  • Safeguarding policy.pdf
  • Welfare policy.pdf

And here is what I have tried:

private void GenerateFolder()
{
    folder_path = Server.MapPath(BaseFolder);
    _folder_view = new StringBuilder();

    if (Directory.Exists(folder_path))
    {
        DirectoryInfo info = new DirectoryInfo(folder_path);
        FileInfo[] files = info.GetFiles().OrderByDescending(p => p.FullName).ToArray();

        foreach (FileInfo file in files)
        { 
            doStuff();
        }
    }

    folder_view.Text = _folder_view.ToString();
}

With this code, the PDFs whose names begin with a date are ordered in descending order (by date) which is what I want. But the other PDFs whose names do not begin with a date are not ordered the way I would like (alphabetically). Is there a way to accomplish my dual-sorting objective?

like image 546
Handy Andy Mutter Avatar asked Apr 18 '19 11:04

Handy Andy Mutter


1 Answers

I would create a custom class that parses out the date and the rest of the filename in to separate properties, you can then use OrderByDescending and ThenBy to sort on these individual properties.

public class ParsedFilename
{
    public ParsedFilename(string filename)
    {
        FullName = filename;
        if (filename.Length >= 12 &&
            DateTime.TryParse(filename.Substring(0, 10), out var date))
        {
            Date = date;
            Name = filename.Substring(11);
        }
        else
        {
            Date = null;
            Name = filename;
        }
    }

    public DateTime? Date { get; }
    public string Name { get; }
    public string FullName { get; }
}

You can use it like this:

var data = new List<string>(new[]
    {
        "2019-01-12 Meeting minutes.pdf",
        "Safeguarding policy.pdf",
        "2017-04-27 Meeting minutes.pdf",
        "2018-06-02 Meeting minutes.pdf",
        "2017-12-13 Meeting agenda.pdf",
        "Privacy policy.pdf",
        "Welfare policy.pdf",
        "2018-11-19 Meeting agenda.pdf"
    });

var parsedData = data.Select(d => new ParsedFilename(d));

var sortedData = parsedData.OrderByDescending(d => d.Date)
                           .ThenBy(d => d.Name);

var output = sortedData.Select(d => d.FullName);

It produces the following output:

2019-01-12 Meeting minutes.pdf
2018-11-19 Meeting agenda.pdf
2018-06-02 Meeting minutes.pdf
2017-12-13 Meeting agenda.pdf
2017-04-27 Meeting minutes.pdf
Privacy policy.pdf
Safeguarding policy.pdf
Welfare policy.pdf

Depending on the formats of the filenames in your directory, you may have to add some more robust parsing.

like image 135
Bradley Uffner Avatar answered Oct 23 '22 05:10

Bradley Uffner