Skip to content

Instantly share code, notes, and snippets.

@sphingu
Created June 15, 2013 07:19
Show Gist options
  • Save sphingu/5787251 to your computer and use it in GitHub Desktop.
Save sphingu/5787251 to your computer and use it in GitHub Desktop.
Numeric Comparer for Sorting array numerically
public class NumericComparer : System.Collections.IComparer
{
public NumericComparer()
{ }
public int Compare(object x, object y)
{
if ((x is string) && (y is string))
{
return StringLogicalComparer.Compare((string)x, (string)y);
}
return -1;
}
}
public class StringLogicalComparer
{
public static int Compare(string s1, string s2)
{
//get rid of special cases
if ((s1 == null) && (s2 == null)) return 0;
else if (s1 == null) return -1;
else if (s2 == null) return 1;
if ((s1.Equals(string.Empty) && (s2.Equals(string.Empty)))) return 0;
else if (s1.Equals(string.Empty)) return -1;
else if (s2.Equals(string.Empty)) return -1;
//WE style, special case
bool sp1 = Char.IsLetterOrDigit(s1, 0);
bool sp2 = Char.IsLetterOrDigit(s2, 0);
if (sp1 && !sp2) return 1;
if (!sp1 && sp2) return -1;
int i1 = 0, i2 = 0; //current index
int r = 0; // temp result
while (true)
{
bool c1 = Char.IsDigit(s1, i1);
bool c2 = Char.IsDigit(s2, i2);
if (!c1 && !c2)
{
bool letter1 = Char.IsLetter(s1, i1);
bool letter2 = Char.IsLetter(s2, i2);
if ((letter1 && letter2) || (!letter1 && !letter2))
{
if (letter1 && letter2)
{
r = Char.ToLower(s1[i1]).CompareTo(Char.ToLower(s2[i2]));
}
else
{
r = s1[i1].CompareTo(s2[i2]);
}
if (r != 0) return r;
}
else if (!letter1 && letter2) return -1;
else if (letter1 && !letter2) return 1;
}
else if (c1 && c2)
{
r = CompareNum(s1, ref i1, s2, ref i2);
if (r != 0) return r;
}
else if (c1)
{
return -1;
}
else if (c2)
{
return 1;
}
i1++;
i2++;
if ((i1 >= s1.Length) && (i2 >= s2.Length))
{
return 0;
}
else if (i1 >= s1.Length)
{
return -1;
}
else if (i2 >= s2.Length)
{
return -1;
}
}
}
private static int CompareNum(string s1, ref int i1, string s2, ref int i2)
{
int nzStart1 = i1, nzStart2 = i2; // nz = non zero
int end1 = i1, end2 = i2;
ScanNumEnd(s1, i1, ref end1, ref nzStart1);
ScanNumEnd(s2, i2, ref end2, ref nzStart2);
int start1 = i1; i1 = end1 - 1;
int start2 = i2; i2 = end2 - 1;
int nzLength1 = end1 - nzStart1;
int nzLength2 = end2 - nzStart2;
if (nzLength1 < nzLength2) return -1;
else if (nzLength1 > nzLength2) return 1;
for (int j1 = nzStart1, j2 = nzStart2; j1 <= i1; j1++, j2++)
{
int r = s1[j1].CompareTo(s2[j2]);
if (r != 0) return r;
}
// the nz parts are equal
int length1 = end1 - start1;
int length2 = end2 - start2;
if (length1 == length2) return 0;
if (length1 > length2) return -1;
return 1;
}
//lookahead
private static void ScanNumEnd(string s, int start, ref int end, ref int nzStart)
{
nzStart = start;
end = start;
bool countZeros = true;
while (Char.IsDigit(s, end))
{
if (countZeros && s[end].Equals('0'))
{
nzStart++;
}
else countZeros = false;
end++;
if (end >= s.Length) break;
}
}
}//EOC
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment