Using IComparer to Sort a String Array

J

Jeta

Hello All,

I stumped and I need some help. I have an unsorted string array that looks
something like:
AA
XXX
Z

and I would like to sort it like:
Z
AA
XXX

or like:
XXX
AA
Z

My research has lead me to using the IComparer interface. What I am having
difficulties with is developing a class that will take an unsorted string
array (as noted above) and return a sorted string array (as noted above)
using the IComparer interface.

Thanks in Advance!
 
M

Marc Gravell

I'm assuming that "XXX" is some secial value that you want to
highlight?

Anyways... something like below.

Marc

using System;
using System.Collections.Generic;
using System.Collections;

public class XxxComparer : IComparer<string>, IComparer
{
public static readonly IComparer<string> Default = new
XxxComparer();
const string KNOWN_VAL = "XXX";
public int Compare(string lhs, string rhs)
{
if (lhs == KNOWN_VAL)
{
return rhs == KNOWN_VAL ? 0 : -1;
}
else if (rhs == KNOWN_VAL)
{
return 1;
}
return string.Compare(lhs, rhs);
}
int IComparer.Compare(object lhs, object rhs)
{
return Compare(lhs as string, rhs as string);
}
}
static class Program
{
static void Main() {
string[] vals = { "AA", "XXX", "Z" };
Array.Sort<string>(vals, XxxComparer.Default);
foreach (string val in vals)
{
Console.WriteLine(val);
}
}
}
 
B

Ben Voigt [C++ MVP]

Jeta said:
Hello All,

I stumped and I need some help. I have an unsorted string array that
looks something like:
AA
XXX
Z

and I would like to sort it like:
Z
AA
XXX

or like:
XXX
AA
Z

My research has lead me to using the IComparer interface. What I am
having difficulties with is developing a class that will take an
unsorted string array (as noted above) and return a sorted string
array (as noted above) using the IComparer interface.

You probably really want the Comparison(T) delegate, but the List.Sort
method will work with either.

Something like:

int ConvertColumnName(string s)
{
int total = 0;
foreach (char c in s)
total = total * 26 + (c - 'A' + 1);
return total;
}

The for ascending or descending sort:

List<string> l;
l.Sort(delegate (string first, string second) { return
ConvertColumnName(first) - ConvertColumnName(second); });
l.Sort(delegate (string first, string second) { return
ConvertColumnName(second) - ConvertColumnName(first); });
 
J

Jeta

Hi Marc,

Thank you for your response!

In the context of your XxxComparer class, "XXX" has no special meaning. In
Main() is where it becomes important (not the XXX, but the highest
letter(s)) All I need is a "comparer" class to return a sorted array. Once
returned, I would like to procure the highest value from the first or last
element of the array. Note, the unsorted string array that I provided was
just a sample. The unsorted sample array could have looked like the
following examples:

example 1
A
B
C
Z
AA
AZ
AC
AB

example 2
ZZX
ZZY
ZZZ

Also, in your code, you have "using System.Collections.Generic;", I think
this was introduced in .Net 2.0, the company that I work for is making me
compile my "stuff" down to .Net 1.1 I mention this because I am not sure if
your technique will work for .Net 1.1

Thanks Again!
 
I

Ignacio Machin ( .NET/ C# MVP )

Hello All,

I stumped and I need some help. I have an unsorted string array that looks
something like:
AA
XXX
Z

and I would like to sort it like:
Z
AA
XXX

or like:
XXX
AA
Z

My research has lead me to using the IComparer interface. What I am having
difficulties with is developing a class that will take an unsorted string
array (as noted above) and return a sorted string array (as noted above)
using the IComparer interface.

Thanks in Advance!

Hi,

Yes, you need to create a class that implements the IComparer.
There are other ways though, depending of what kind of collection you
have and what version of the framework you are using
If you are using 2.0+ and a generic collectin you can do something
like:

myList.Sort(delegate(string T1, string T2) {
return T1.CompareTo(T2);
});
 
M

Marc Gravell

Re the XXX - I was (and still am) unclear about what the sort order
should be - is this "by length"? because otherwise as far as I am
concerned, AA, XXX, Z is already sorted. The IComparer approach should
work in 1.1, but I don't have any 1.1 tools available to verify; but
the following *might* compile in 1.1 ;-p

using System;
using System.Collections;

public class XxxComparer : IComparer
{
public static readonly IComparer Default = new XxxComparer();
const string KNOWN_VAL = "XXX";
public int Compare(string lhs, string rhs)
{
if (lhs != null && rhs != null)
{
int result = lhs.Length.CompareTo(rhs.Length);
if (result != 0) return result;
}
return lhs.CompareTo(rhs);
}
int IComparer.Compare(object lhs, object rhs)
{
return Compare(lhs as string, rhs as string);
}
}
static class Program
{
static void Main() {
string[] vals = { "AA", "XXX", "Z" };
Array.Sort(vals, XxxComparer.Default);
foreach (string val in vals)
{
Console.WriteLine(val);
}
}
}
 
J

Jeta

...as far as I am concerned, AA, XXX, Z is already sorted.
If the sort is occurring on the first character, you are 100% correct. Using
the AA, XXX, Z example, I see XXX being greater than Z.

FYI, the letters that I am describing are actually revision levels coming
from a CAD drawing. What I am trying to do is get the last revision level
from an array - in this case the last revision level would be XXX

Thanks
 
M

Marc Gravell

If the sort is occurring on the first character, you are 100% correct. Using
the AA, XXX, Z example, I see XXX being greater than Z.

Maybe I'm being really slow today - but would you care to explain
those rules? Why would the last revision be XXX? Is the problem is
that you want 123 to follow 29? In which case, the code I posted last
time might do the job... it compares by length first, and (for equal
length) compares as normal...

Marc
 
J

Jeta

Hi Marc,
No! I was probably not explaining myself clear enough.
XXX was just an example. Actually, the highest revision level is ZZZ for
mechanical engineering CAD drawings and 999 for architectural engineering
CAD drawings. Now you may ask :) why would the last revision level be ZZZ
or 999? My response is it's a company standard.

Our CAD drawings have a placeholder for a maximum of three revision levels.
When a new mechanical engineering CAD drawing is created it's revision level
is "A". When a change is made, to this type of CAD drawing, the revision
level is incremented to the next letter. This process is repeated for each
engineering change.

Since I stated there's a placeholder for a maximum of three revision levels,
revision "D" would replace the revision "A", revision "E" would replace
revision "B" and revision "F" would replace revision "C", etc., etc., etc.

When the last revision is "Z", the next revision would be "AA" followed by
"AB", "AC", "AD", ...,"AZ", "BA", "BB", ...,"BZ", ...,"ZA", ..., "ZZ",
"AAA", ...,"AAZ", etc., etc., etc. So, theoretically a mechanical
engineering CAD drawing could have 17,576 revisions. Will there ever be that
many revision levels? NO WAY!

I hope the above wasn't to much babble!
Yes, Yes, Yes :) I haven't tested your code with numbers, but I have tested
it with letters. Here's an example. Your code will sort the following string
array:
Z
AA
AB

Like this:
AA
AB
Z

I needed it to be sorted like:
Z
AA
AB

After studying your code and other responses, here's what I came up with:
public class sortRevision : IComparer
{
int IComparer.Compare(Object x, Object y)
{
int val = ((new CaseInsensitiveComparer()).Compare(x, y));
string localx = (string)x;
string localy = (string)y;

if (val < 0)
{
if (localx.Length > localy.Length)
val = 1;
}
if (val > 0)
{
if (localx.Length < localy.Length)
val = -1;
}
return val;
}
}

I am calling the above as follows:
Array.Sort(allRevLevels, (IComparer)new sortRevision());

Any suggestions are welcome and greatly appreciated!

Thanks!
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top