'How to Order these list of string according to its version

Adding some sample data

var list0 = new List<string>() { "MAS_Prod_1.2107.0.8","MAS_Prod_1.2107.0.4","MAS_Prod_1.2107.0.7","MAS_Prod_1.2107.0.12", "MAS_Prod_1.2107.0.11", "MAS_Prod_1.2107.0.10","MAS_Prod_1.2107.0.3", "All" };
var list1 = new List<string>() {"All", "master-1.2107.120.0","master-1.2107.124.0", "master-1.2107.136.0","master-1.2107.122.0", "master-1.2107.136.0", "master-1.2107.138.0" };
var list3 = new List<string>() {"All", "users_yingrt_saturn-1.2104.3.2", "users_yingrt_saturn-1.2104.3.4", "users_yingrt_saturn-1.2104.3.5", "users_yingrt_saturn-1.2104.3.7" }

What I tried to solve.

list0 = list0.OrderByDescending(o => o).ToList();
foreach (var i in list0) { Console.WriteLine(i); }

Trying to create some logic to sort the list according to its version mentioned in it. Expected Output : MAS_Prod_1.2107.0.12, MAS_Prod_1.2107.0.11, MAS_Prod_1.2107.0.10, MAS_Prod_1.2107.0.8, MAS_Prod_1.2107.0.7, MAS_Prod_1.2107.0.4, MAS_Prod_1.2107.0.3, All

A similar result for other lists as well. A possible solution can be if will able to Split its version and make a dictionary <key, value> value as version and sort on top of version. Not able to achieve in code. Need some Help!!!



Solution 1:[1]

That looks like semantic versioning. You can create a semver class, parse the version and order by it. It's not very clear if the 1 before the first dot is part of the versioning or the name, but you can easily add another field if it has to be orderable too.

If you can't match the semver pattern, you can return a deafult version. In this case, I'm returning 0.0.0, so it will be the first version and will fulfill your requirements for the All to be the first. If you want to be the last, you can change it so it'll return the int.MaxValue for all properties.

public class SemVer : IComparable<SemVer>
{
    public SemVer()
    {
    }   
    
    public int Major { get; set; }
    public int Minor { get; set; }
    public int Patch { get; set; }
    
    public static SemVer Parse(string input)
    {
        Match match = Regex
            .Match(input, @"(?<major>\d+)\.(?<minor>\d+)\.(?<patch>\d+)$");
        if(match.Success){
            return new SemVer(){
                Major=int.Parse(match.Groups["major"].Value),
                Minor=int.Parse(match.Groups["minor"].Value),
                Patch=int.Parse(match.Groups["patch"].Value),
            };
        }
        return new SemVer();
    }

    public int CompareTo(SemVer other)
    {
        int result = Major.CompareTo(other.Major);
        if(result==0){
            result = Minor.CompareTo(other.Minor);
        }
        if(result==0){
            result = Patch.CompareTo(other.Patch);
        }
        return result;
    }
}

And use like this:

list0 = list0.OrderByDescending(x=>SemVer.Parse(x)).ToList();
list1 = list1.OrderByDescending(x=>SemVer.Parse(x)).ToList();
list3 = list3.OrderByDescending(x=>SemVer.Parse(x)).ToList();

Solution 2:[2]

You should write a class to store Name, Major version, Minor version and Mini version then Order it by each property.

public class Version
{
    public string Name { get; set; }
    public int Major { get; set; } = int.MinValue;
    public int Minor { get; set; } = int.MinValue;
    public int Mini { get; set; } = int.MinValue;
   
    public Versions(string version)
    { 
        var splittedVersion = version.Split('.');
        this.Name = splittedVersion[0];
        if(splittedVersion.Length == 4)  //Condition check for "All"
        {
            this.Major = splittedVersion[1];
            this.Minor = splittedVersion[2];
            this.Mini = splittedVersion[3];
        }
    }
    
    public override string ToString()
    {
         if(this.Major == int.MinValue && this.Major == int.MinValue && this.Mini == int.MinValue)
              return this.Name;
          else
              return $"{this.Name}.{this.Major}.{this.Minor}.{this.Mini}";
    }
     
    
}

Now Parse your list elements into Version class and order it based on versions. Like,

using System.Linq;

....
var results = list0 
      .Select(x => new Version(x)) //Convert list of string into list of Version class
      .OrderByDescending(x => x.Major) //First order by Major version
      .ThenByDescending(x => x.Minor)  //Then order by Minor version
      .ThenByDescending(x => x.Mini)  //Then order by mini version
      .ToList();   //Convert IEnumerable to List

Now print updated result,

foreach(var result in results)
    Console.WriteLine(result);

Solution 3:[3]

If you need a more advanced SemVer-sorting, I can recommend you to use NuGet.Versioning or my own package Vernuntii.SemVer. Both have a static SemanticVersion.Parse(versionStringToParse) method and both have a implementation of an IComparer<SemanticVersion> called VersionComparer (Nuget.Versioning) or SemanticVersionComparer (Vernuntii.SemVer).

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1
Solution 2
Solution 3 Teroneko