2

I'm having a list which has some versions in it .

sample data :

"4.5","2.1","2.2.1","7.5","7.5.3","N/A","2.3.4.5"

As you can see the data , i'm trying to sort list by Descending tough 3.8.5 is invalidnumber & NA is a invalid one .

Code :

decimal result;
var sortedVData = vData.OrderByDescending(v => decimal.TryParse(v.vCode, out result) ? Convert.ToDecimal(v.vCode) : decimal.MaxValue);

Output : "NA" , "7.5.3" , '2.3.4.5' , "2.2.1" , '7.5' , '4.5' , '2.1'

As you see in my else(:) condition i'm doing decimal.MaxValue to make NA to come top if there is invalid value (any string with text) but 2.2.1 should be a exception and should work as number(tough 2.2.1 or any number having multiple decimals a is invalid in version's point of view i want them made conditionally valid .

Expected Result : "NA" , "7.5.3" , "7.5" , "4.5" ,"2.3.4.5" ,"2.2.1" , "2.1"

Wai Ha Lee
  • 8,598
  • 83
  • 57
  • 92
super cool
  • 6,003
  • 2
  • 30
  • 63

3 Answers3

7

You can use Version.TryParse and this extension method for LINQ queries:

public static Version TryGetVersion(this string item)
{
    Version ver;
    bool success = Version.TryParse(item, out ver);
    if (success) return ver;
    return null;
}

Then the complete query is simple:

var sortedVData = vData
    .Select(v => new { Obj = v, Version = v.vCode.TryGetVersion() })
    .OrderBy(x => x.Version != null)    // first all invalid versions
    .ThenByDescending(x => x.Version)   // then by version descending
    .Select(x => x.Obj);

So actually it would be better to store versions instead of strings in your class.

It's better to use this extension in LINQ queries than using a local variable.

Community
  • 1
  • 1
Tim Schmelter
  • 450,073
  • 74
  • 686
  • 939
  • @waiHaLee comment helped me to frame what i need & your answer was absolutely spot on & clean . – super cool Jan 05 '16 at 11:21
  • `v.vCode.TryGetVersion()` will return null when i have `NA` in the list & end list will have null instead of `NA` on top – super cool Jan 05 '16 at 12:04
  • @supercool: No, i have used `.OrderBy(x => x.Version != null)` which moves the invalid versions to the top. You could also use `.OrderByDescending(x => x.Version == null)` or `.OrderBy(x => x.Version == null ? 0 : 1)`. The trick is that a comparison returns `true` or `false` and `true` has a higher value than `false`. That's why `.OrderBy(x => x.Version != null)` moves the valid versions to the bottom. You need `OrderBy` **and** `ThenByDescending` as shown above. – Tim Schmelter Jan 05 '16 at 12:08
  • humm yes i got the ordering part, its clever . when i tried using the same logic in my real code (i'm binding to dropdown , each list item has many entities i.e version etc not given in the sample ) there seem to be a slightest of issue . anyway i'll workaround it . cheers mate – super cool Jan 05 '16 at 12:19
1

Like @WaiHaLee says, you can use Version, and it implements IComparable, so you can just do this:

static void Main(string[] args)
    {
        var data = new[] {"4.5","2.1","2.2.1","7.5","7.5.3",@"N/A","2.3.4.5"};
        foreach(var v in data.OrderByDescending(OrderVersion))
            Console.WriteLine(v);
    }

    private static IComparable OrderVersion(string arg)
    {
        //Treat N/A as highest version
        if (arg == "N/A")
            return new Version(Int32.MaxValue,Int32.MaxValue); 
        return Version.Parse(arg);
    }
Mikael Nitell
  • 1,069
  • 6
  • 16
1
public class VersionsComparer: IComparer<string>
{
    public int Compare(string x, string y)
    {

        if (x.ToLower() == @"n/a")
        {
            if (y.ToLower() == @"n/a")
                return 0;

            return -1;
        }

        if (y.ToLower() == @"n/a")
        {
            if (x.ToLower() == @"n/a")
                return 0;

            return 1;
        }

        var verX = Version.Parse(x);
        var verY = Version.Parse(y);

        return verX.CompareTo(verY);
    }
}

class Program
{
    static void Main(string[] args)
    {
        var versions = new[] { "4.5", "2.1", "2.2.1", "7.5", "7.5.3", @"N/A", "2.3.4.5" };


        foreach (var v in versions.OrderByDescending(v => v, new VersionsComparer()))
        {
            Console.WriteLine(v);
        }
    }


}
Yaugen Vlasau
  • 2,148
  • 1
  • 17
  • 38