Warm tip: This article is reproduced from serverfault.com, please click

Hierarchical and numerical ordering of strings made from delimited integers (C#)

发布于 2020-11-25 22:02:07

I have a list of folder names that represent chapters, subchapters, sections, paragraphs and lines in a specification. A small sample of these folders looks like the following.

  • 1_1_1
  • 1_1_12
  • 1_1_2
  • 1_2_1
  • 1_2_1_3_1
  • 1_2_2

I need to write a function that sorts these numerically and taking account for hierarchical nesting. For instance the correct output of sorting the above would be.

  1. 1_1_1
  2. 1_1_2
  3. 1_1_12
  4. 1_2_1
  5. 1_2_1_3_1
  6. 1_2_2

Since this is very much the same way version numbers are sorted I have tried the following code which worked until it attempts to process an input with more than 4 sections (i.e. 1_2_1_3_1)

private List<Resource> OrderResources(List<Resource> list)
    {
        return list.OrderBy(v => System.Version.Parse(v.Id.Replace('_', '.'))).ToList();
    }

The error I get is

System.ArgumentException : Version string portion was too short or too long. (Parameter 'input')
Questioner
Rob S.
Viewed
0
Stanislav 2020-11-26 06:57:39

Sorting is possible if you add n characters 0 between the digits.

Also You can use long and move the numbers n digits to the left, but then there will be a limit on the length of the number.

static void Main(string[] args)
{
    var chapter = new List<string>();
    chapter.Add("1_1_1");
    chapter.Add("1_1_12");
    chapter.Add("1_1_2");
    chapter.Add("1_2_1");
    chapter.Add("1_2_1_3_1");
    chapter.Add("1_2_2");
    var result = chapter.OrderBy(x=>SortCalc(x)).ToArray();
    foreach (var s in result)
    {
        Console.WriteLine($"{s}->{SortCalc(s)}");
    }
}

private static string SortCalc(string x, int count = 3)
{
    var array = x.Split('_').ToList();
    
    for (var index = 0; index < array.Count; index++)
    {
        var length = count - array[index].Length;
        if (length <=0)
            continue;
        array[index] = new string('0', length)+ array[index];
    }

    var num = string.Join("", array);
    return num;
}

Output will be

1_1_1->001001001
1_1_2->001001002
1_1_12->001001012
1_2_1->001002001
1_2_1_3_1->001002001003001
1_2_2->001002002