stevieb
stevieb

Reputation: 9306

Sorting a list of numeric strings with numerous decimal points

I've got a situation where I need to sort a list of strings that contain three decimal parts in descending order from left-to-right. The real code is a dictionary of <string, object>, but I've simplified it here as I'm in the same predicament either way.

Straight to the code:

using System;
using System.Collections.Generic;

class Program
{
    static void Main()
    {
        List<string> perlVersions = new List<string>();

        perlVersions.Add("5.26.1_32");
        perlVersions.Add("5.24.1_32");
        perlVersions.Add("5.8.1_64");
        perlVersions.Add("5.24.2_64");

        perlVersions.Sort();
        perlVersions.Reverse();
        foreach (string str in perlVersions) Console.WriteLine(str);
    }
}

Output:

5.8.1_64
5.26.1_32
5.24.2_64
5.24.1_32

Now, Everything works well, except that the 5.8.1_64, due to the second part of the number being lower than all others, should be at the bottom.

Is there a special sorting trick I'm missing, or is there a way to further break apart the strings and sort on each individual element?

Upvotes: 3

Views: 1306

Answers (4)

InBetween
InBetween

Reputation: 32780

Or a fully query syntax version:

var b = from v in perlVersions
        let ii = v.Split(".")
                  .Take(2)
                  .Select(i => int.Parse(i)).ToArray()
        orderby ii[0] descending
        orderby ii[1] descending
        select v;

Upvotes: 1

Roman Marusyk
Roman Marusyk

Reputation: 24609

Try this one

string[] separator = new string[] { "." };  
var result = perlVersions
   .OrderByDescending(s => int.Parse(s.Split(separator, StringSplitOptions.None)[1]))
   .OrderByDescending(s => int.Parse(s.Split(separator, StringSplitOptions.None)[0]))
   .ToList();

Upvotes: 2

Aleks Andreev
Aleks Andreev

Reputation: 7054

You can do you custom sort using Linq
To do so split your string by '.' and then extend each part with '0'

List<string> perlVersions = new List<string>();

perlVersions.Add("5.26.1_32");
perlVersions.Add("5.24.1_32");
perlVersions.Add("5.8.1_64");
perlVersions.Add("5.24.2_64");

perlVersions = perlVersions
    .OrderByDescending(v => string.Concat(v.Split('.').Select(x => x.PadLeft(5, '0'))))
    .ToList();

This will (temporary) convert "8" to "00008" and "24" to "00024", which make your sort working as expected.

Upvotes: 0

mm8
mm8

Reputation: 169340

You could for example split the string and treat the different parts an integers, and then sort by these using some LINQ:

static void Main()
{
    List<string> perlVersions = new List<string>();

    perlVersions.Add("5.26.1_32");
    perlVersions.Add("5.24.1_32");
    perlVersions.Add("5.8.1_64");
    perlVersions.Add("5.24.2_64");

    perlVersions = perlVersions
        .Select(x => x.Split(new char[] { '.' }))
        .Select(x =>
        {
            string[] lastParts = x[2].Split(new char[] { '_' });
            return new { a = Convert.ToInt32(x[0]), b = Convert.ToInt32(x[1]), c = Convert.ToInt32(lastParts[0]), d = Convert.ToInt32(lastParts[1]) };
        })
        .OrderBy(x => x.a).ThenBy(x => x.b).ThenBy(x => x.c).ThenBy(x => x.d)
        .Select(x => string.Format("{0}.{1}.{2}_{3}", x.a, x.b, x.c, x.d))
        .ToList();

    perlVersions.Reverse();
    foreach (string str in perlVersions) Console.WriteLine(str);
}

Upvotes: 2

Related Questions