0

first of all, im still kinda new to coding and have not that much knowledge ^^ So here is my problem, I need to create a class/method that can sort a list, that look like this:

.Add("1");
.Add("1.1");
.Add("1.2");
.Add("1.1.1-1");
.Add("1.1.1-1usa");
.Add("7.2");
.Add("8.");
.Add("9.");
.Add("10.1)

the list should be ascend(?) meaning, it starts with the lowest number going up to the highest.

I tried to make char arrays out of them and then compare each char with an if-statement. some mor informations: 1.1.1 > 1.1 and as you can see, there are also letters inside. If someone has an idea I would be very thankful for every tip :)

NOTE: if I would sort it like list.Sort();, 10.1 wouldnt come right after 9, instead its bewtween 1.1 and 2.1 for example

  • 1
    First convert the `strings` to a numeric type. How you do this depends on encoding, which is pretty complex (UTF, ASCII, region, etc.). Then, my advice would be to search 'bubble sort'. – dmedine Feb 04 '22 at 07:53
  • @dmedine: Given that there can be letters in there (the "usa" part) and a variable (arbitrary?) number of segments, I don't see that converting to a numeric type will work in an easy-to-understand way. Better IMO to implement an `IComparer`. – Jon Skeet Feb 04 '22 at 08:04
  • @JonSkeet, ah, yes, you are certainly right. Although, I'm pretty sure `IComparer` also converts the strings to numeric values according to some rules of encoding ;-) – dmedine Feb 04 '22 at 08:25
  • 2
    @dmedine: It's an interface. It doesn't "do" anything. A particular implementation *could* convert the strings to numeric values - but that seems unlikely to be a useful option here. – Jon Skeet Feb 04 '22 at 08:28
  • Is the list above already ordered so the expected result or unordered? If the former, why `1.2` comes before `1.1.1-1`? If this is a version like system 1.2 should come after 1.1.1 – Tim Schmelter Feb 04 '22 at 08:46
  • Search for "natural sort", for instance [here](https://stackoverflow.com/questions/248603/natural-sort-order-in-c-sharp) – Hans Kesting Feb 04 '22 at 09:53

3 Answers3

2

The cleanest approach here is to implement comparer between two items. See:How to use a custom Comparer to sort an Array in a different lexical order?

The basic idea is that you need to implement the comparison between two items:

public static int CompareStrings(string s1, string s2)
{
    // TODO: your code here
    // since your string represents version numbers to avoid 
    //comparing them lexicographically first parse them to numbers. 
}

And now you can sort using this comparator:

string[] myStrings = { ... };
Array.Sort(myStrings, CompareStrings);

Another similar option is to implement your own comparator class that implements IComparer<string> and pass it to .OrderBy(x => x.Name, new MySorter());

Yosi Dahari
  • 6,794
  • 5
  • 24
  • 44
  • Thank you very much for your help. But I still have an important probleme. Everytime I try to sort the array/list it comes to the following issue: .Add("10.1") will come in the wrong order. example output: 1.1 1.2 10.1 2.1 ... 9.1 Or did understand something wrong? Thanks again :) – 247Munchies Feb 04 '22 at 11:37
  • @247Munchies Post your implementation of `CompareStrings` or `IComparer`, whichever you have chosen out of Yosi's answer. – Orion Feb 04 '22 at 13:33
0

I have used basic alphabetic sorting and this is the result:

1
1.1
1.1.1-1
1.1.1-1usa
1.2
7.2
8.
9.

As you can see:

1 < 1.1 < 1.1.1-1* < 1.2 < 7.2 < 8. < 9. 

       // 1.1.1-1* means: 
       // anything, starting with 1.1.1-1

I believe we can agree on that. As far as the letters are concerned:

1.1.1-1 < 1.1.1-1usa

Also this seems logical, because nothing comes before something.

So it looks like basic alphabetic sorting does the trick, or do you disagree?

Dominique
  • 16,450
  • 15
  • 56
  • 112
  • 3
    How would "1.15" work there? I'm pretty sure it would come between 1.1.1-1usa and 1.2, instead of after 1.2 which I expect to be the desirable outcome. Sure, that's not an example that's been presented, but it seems an obvious one to consider. Or even more simply: "10.1". – Jon Skeet Feb 04 '22 at 08:05
  • @JonSkeet: your remark is spot on! "1.15" is placed indeed before "1.2", which is exactly the reason why such kind of numbering generally is unadvised: it's more common to chech what the maximum value might be (one digit, two or more digits?) and use this number of digits for every entry. In the mentioned case, this would result in the following list: `"01", "01.01", "01.02", "01.01.01-01", "01.01.01-01usa", "07.02", "08.", "09.", "01.15"`. – Dominique Feb 04 '22 at 08:22
  • That's fine when that's the realm you're in - but it doesn't look like that's the task (and it does have downsides, in terms of needing to know maximum values beforehand). The question as asked, with the admittedly-inferred expectation that "10.1" should come at the end, is still answerable - and useful, e.g. to compare SemVer versions. – Jon Skeet Feb 04 '22 at 08:30
  • @JonSkeet: exactly. There might be the need to show the values as mentioned (no leading zeroes allowed). In that case I have worked with double systems: I was showing values like "1.1" and "1.15" but in background I was working with "01.01" and "01.15". – Dominique Feb 04 '22 at 08:48
  • Ah, right. Yes, if you can work out what the maximal values should be, that seems like a reasonable option. I'm still not sure that your answer as it stands (bearing in mind that comments are ephemeral, and can be deleted at any time) is really the best advice for the OP though. – Jon Skeet Feb 04 '22 at 09:09
  • Unfortunately its not working for me. Example: if I would .Add("10.1"), the fresh added value would come between 1.1 and 2.1, so its not coming after 9.1 for example. I should have said that before, sorry. But Im very thankful for all the comments and ideas :) – 247Munchies Feb 04 '22 at 09:45
0

Again a big thanks to everyone. This is the solution i decided to take advantage of:

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