Created
June 15, 2013 07:19
-
-
Save sphingu/5787251 to your computer and use it in GitHub Desktop.
Numeric Comparer for Sorting array numerically
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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