0

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);
    }
}
Guru Stron
  • 102,774
  • 10
  • 95
  • 132
ssinfod
  • 975
  • 2
  • 15
  • 31
  • Have you run it in the debugger to make sure the comparer is running? Is the regex splitting the values as you expect? – D Stanley Jul 20 '21 at 13:37
  • Also I don't see any groupings in your regex, so `Groups[1]` and `Groups[2]` should be throwing an exception. – D Stanley Jul 20 '21 at 13:39
  • Indeed, the code is broken. I was just not sure how to sort two times with the IComparer. – ssinfod Jul 20 '21 at 15:21

2 Answers2

2

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
Magnetron
  • 7,495
  • 1
  • 25
  • 41
0

You can do something like this:

public class YourClassName
{
    public string PackageName { get; set; }
    public string Pipe { get; set; }
    public string Version { get; set; }
}

Load your data into list to sort

List<YourClassName> list = souce of data;
list = SortList<YourClassName>(list, "PackageName");

SortList Method:

public List<YourClassName> SortList<TKey>(List<YourClassName> list, string sortBy)
{
    PropertyInfo property = list.GetType().GetGenericArguments()[0].GetProperty(sortBy);
    return list.OrderBy(e => property.GetValue(e, null)).ToList<YourClassName>();
}
Harshad Raval
  • 79
  • 2
  • 10