Search code examples
c#.netalgorithmsortingicomparer

C# / Sorting a text file / IComparer / Custom sort


I have a text file that I want to be sorted.

Each line has a package name, a pipe and a version number.

Examples:

  1. AutoFixture|4.15.0
  2. Castle.Windsor.Lifestyles|0.3.0

I tried to use the default list.Sort() method but I obtained:

AutoFixture|4.15.0
Castle.Core|3.3.0
Castle.Windsor.Lifestyles|0.3.0
Castle.Windsor|3.3.0
FluentAssertions|5.10.3

Instead of

AutoFixture|4.15.0
Castle.Core|3.3.0
Castle.Windsor|3.3.0
Castle.Windsor.Lifestyles|0.3.0
FluentAssertions|5.10.3

As shown, I would like "Castle.Windsor" to appear before "Castle.Windsor.Lifestyles". I'm pretty sure I have to use the IComparer but I can't find a way to get the shorter name first.

So far, I created a custom sort like this which is not working..

public class PackageComparer : IComparer<string>
{
    // Assume that each line has the format: name|number
    private readonly Regex packageRegEx = new Regex(@"[\w.]+\|[\d.]+", RegexOptions.Compiled);

    public int Compare(string x, string y)
    {
        var firstPackage = this.packageRegEx.Match(x);
        var firstLeft = firstPackage.Groups[1].Value;
        var firstRight = firstPackage.Groups[2].Value;

        var secondPackage = this.packageRegEx.Match(y);
        var secondLeft = secondPackage.Groups[1].Value;
        var secondRight = secondPackage.Groups[2].Value;

        if (firstLeft < secondLeft)
        {
            return -1;
        }

        if (firstRight > secondLeft)
        {
            return 1;
        }

        return string.CompareOrdinal(firstSceneAlpha, secondSceneAlpha);
    }
}

Solution

  • Well, you can use Linq, split by the pipe and order by the package name then by the versioning:

    var input = @"AutoFixture|4.15.0
    Castle.Core|3.3.0
    Castle.Windsor.Lifestyles|0.3.0
    Castle.Windsor|3.3.0
    FluentAssertions|5.10.3
    Castle.Core|3.1.0";
    
    var list = input.Split(new string[]{"\r\n","\n"},StringSplitOptions.None).ToList();
    
    list = list
        .OrderBy(x => x.Split('|')[0])
        .ThenBy(x => new Version(x.Split('|')[1]))
        .ToList();
    

    Outputs:

    AutoFixture|4.15.0
    Castle.Core|3.1.0
    Castle.Core|3.3.0
    Castle.Windsor|3.3.0
    Castle.Windsor.Lifestyles|0.3.0
    FluentAssertions|5.10.3