I have array list of strings:
"1A", "12A", "12B", "6", "A", "5B", "B", "13"
.
If I do myList.Sort();
then I get:
"1A", "12A", "12B", "13", "5B", "6", "A", "B"
.
But what I need is first sort by numbers in front, then by letter:
"1A", "5B", "6", "12A", "12B", "13", "A", "B"
.
I could use
public class CustomComparer : IComparer
{
Comparer _comparer = new Comparer(System.Globalization.CultureInfo.CurrentCulture);
public int Compare(object x, object y)
{
// Convert string comparisons to int
return _comparer.Compare(Convert.ToInt32(x), Convert.ToInt32(y));
}
}
But it throws exception. How do I get what I need?
To sort the ArrayList, you need to simply call the Collections. sort() method passing the ArrayList object populated with country names. This method will sort the elements (country names) of the ArrayList using natural ordering (alphabetically in ascending order).
Approach: An ArrayList can be Sorted by using the sort() method of the Collections Class in Java. This sort() method takes the collection to be sorted as the parameter and returns a Collection sorted in the Ascending Order by default.
Java's default sorting The mapping of characters to code points is available on Unicode site . General rule is that numbers come before capital letters, and capital letters come before lowercase letters.
Your comparer is too simplistic. Your comparison needs to split each value into the number and the rest, then compare the numbers first, then the strings if they're equal. So it would be something like:
public sealed class NumberStringComparer : IComparer<string>
{
public int Compare(string x, string y)
{
return NumberString.Parse(x).CompareTo(NumberString.Parse(y));
}
private struct NumberString : IComparable<NumberString>
{
private readonly int? number;
private readonly string text;
private NumberString(int? number, string text)
{
this.number = number;
this.text = text;
}
internal static NumberString Parse(string text)
{
// TODO: Find where the digits stop, parse the number
// (if there is one), call the constructor and return a value.
// (You could use a regular expression to separate the parts...)
}
public int CompareTo(NumberString other)
{
// TODO: Compare numbers; if they're equal, compare
// strings
}
}
}
If you have problems with either of the TODOs (after spending some time trying), you can ask for more specific help - but this is the general approach I'd use.
You cannot simply pass a string "1A"
or "5B"
to Convert.ToInt32(x)
, because it has a portion that is not part of an Int32
.
Instead, you should first split the string into two parts - the digits and everything else, and do the comparison with tie breaks.
One way of doing it would be writing two helper methods, and then using LINQ's OrderBy
and ThenBy
:
static int ExtractPrefix(string s) {
// Parse the digits and stop; return the number
}
static string ExtractSuffix(string s) {
// Skip digits, and return everything else
}
...
var sorted = unsorted.OrderBy(ExtractPrefix).ThenBy(ExtractSuffix).ToList();
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With