C
C#2w ago
.tree

Sorthing house numbers of type string

Say you have a string property for house numbers (1, 98, 24b) and want to sort them. How can you sort them by number as well as by letter? If I just sort them with OrderBy I get 1, 138, 24 which isn't correct.
4 Replies
Sehra
Sehra2w ago
what you are looking for is natural sort order
Angius
Angius2w ago
I'd probably create my own HouseNumber struct or class, with Number and Letter properties Then a custom comparer in it
.tree
.treeOP2w ago
Thanks, both suggestions seem plausible
Sehra
Sehra2w ago
i knew i had written natural sort at some point, found some old code
public class NaturalComparer : IComparer<string>
{
private static readonly Regex _parts = new(@"(\d+)|(\D+)");

public int Compare(string x, string y)
{
var xenum = _parts.EnumerateMatches(x);
var yenum = _parts.EnumerateMatches(y);

while (xenum.MoveNext() && yenum.MoveNext())
{
var xspan = x.AsSpan(xenum.Current.Index, xenum.Current.Length);
var yspan = y.AsSpan(yenum.Current.Index, yenum.Current.Length);
var comp = ComparePart(xspan, yspan);
if (comp != 0) return comp;
}

return xenum.MoveNext() ? 1 : yenum.MoveNext() ? -1 : 0;

static int ComparePart(ReadOnlySpan<char> a, ReadOnlySpan<char> b)
{
if (int.TryParse(a, out var aval) && int.TryParse(b, out var bval))
{
return aval.CompareTo(bval);
}

return a.CompareTo(b, StringComparison.CurrentCultureIgnoreCase);
}
}
}
public class NaturalComparer : IComparer<string>
{
private static readonly Regex _parts = new(@"(\d+)|(\D+)");

public int Compare(string x, string y)
{
var xenum = _parts.EnumerateMatches(x);
var yenum = _parts.EnumerateMatches(y);

while (xenum.MoveNext() && yenum.MoveNext())
{
var xspan = x.AsSpan(xenum.Current.Index, xenum.Current.Length);
var yspan = y.AsSpan(yenum.Current.Index, yenum.Current.Length);
var comp = ComparePart(xspan, yspan);
if (comp != 0) return comp;
}

return xenum.MoveNext() ? 1 : yenum.MoveNext() ? -1 : 0;

static int ComparePart(ReadOnlySpan<char> a, ReadOnlySpan<char> b)
{
if (int.TryParse(a, out var aval) && int.TryParse(b, out var bval))
{
return aval.CompareTo(bval);
}

return a.CompareTo(b, StringComparison.CurrentCultureIgnoreCase);
}
}
}

Did you find this page helpful?