0

I have a flyerPages list which I pull from my database into a list as seen here:

var flyerPages = _flyerPageRepository.FindAllPagesAsync(_flyerId);

I then do the following to order them:

flyerPages.OrderBy(x => x.DocumentName);

This is my result:

DE9320_1_1_.txt
DE9320_1_2_.txt
DE9320_10_1_.txt
DE9320_10_2_.txt
DE9320_11_1_.txt
DE9320_11_2_.txt
DE9320_4_1_.txt
DE9320_4_2_.txt
DE9320_5_1_.txt
DE9320_5_2_.txt
DE9320_6_1_.txt
DE9320_6_2_.txt
DE9320_7_1_.txt
DE9320_7_2_.txt
DE9320_8_1_.txt
DE9320_8_2_.txt

The first number in the filename represents the page number the second represents the part of the page so DE9320_1_1_.txt is page 1 part 1, it can also be shown as DE9320_01_1_.txt etc. Sometimes there is only one part and it is shown as DE9320_1.txt or DE9320_01.txt. Because I am using a string the 10th page comes before the second. Now of course I can just grab the numbers from the middle and sort them but I was wondering is there a way to use only a linq statement to achieve this? If not what would be an easier method then going through each string and extracting the numbers from the middle?

Adil15
  • 405
  • 1
  • 5
  • 15
  • I thougt a natural language sort would do it, but if your data in incosistent (`_01_ vs _1_` - because something like `_04_1` would sort before `_1_` ) it won't because of that. Can you programatically make the file names consistent? Or could you add a sort key to the FlyerPages class? – Kevin Jul 27 '22 at 21:40
  • @Kevin I can definitely make the file names consistent – Adil15 Jul 28 '22 at 01:24
  • 1
    Sorry I can post an answer but you can do like this (fp is an instance of FlyerPage): `var sorted = flyerPages.OrderByAlphaNumeric(fp => fp.DocumentName); public static IOrderedEnumerable OrderByAlphaNumeric(this IEnumerable source, Func selector) { int max = source .SelectMany(i => Regex.Matches(selector(i), @"\d+").Cast().Select(m => (int?)m.Value.Length)) .Max() ?? 0; return source.OrderBy(i => Regex.Replace(selector(i), @"\d+", m => m.Value.PadLeft(max, '0'))); }` – Kevin Jul 28 '22 at 11:02
  • Hey Kevin thanks for the help! This ended up solving my answer. Unfortunately I cant choose it :( – Adil15 Jul 29 '22 at 15:53
  • No problem, just glad it helped!! – Kevin Jul 29 '22 at 22:31

1 Answers1

1

Is this what your are looking for

           string[] inputs = {
                "DE9320_1_1_.txt",
                "DE9320_1_2_.txt",
                "DE9320_10_1_.txt",
                "DE9320_10_2_.txt",
                "DE9320_11_1_.txt",
                "DE9320_11_2_.txt",
                "DE9320_4_1_.txt",
                "DE9320_4_2_.txt",
                "DE9320_5_1_.txt",
                "DE9320_5_2_.txt",
                "DE9320_6_1_.txt",
                "DE9320_6_2_.txt",
                "DE9320_7_1_.txt",
                "DE9320_7_2_.txt",
                "DE9320_8_1_.txt",
                "DE9320_8_2_.txt"
            };

            string[] sorted = inputs.Select(x => new { filename = x, splitArray = x.Split(new char[] { '_' }) })
                .OrderBy(x => x.splitArray[0])
                .ThenBy(x => int.Parse(x.splitArray[1]))
                .ThenBy(x => int.Parse(x.splitArray[2]))
                .Select(x => x.filename)
                .ToArray();
jdweng
  • 33,250
  • 2
  • 15
  • 20