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

2 Answers 2

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
Sign up to request clarification or add additional context in comments.

1 Comment

Thanks, it was perfect for my need. Greetings
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>();
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.