Sorting Array using Icomparable

  • Thread starter Thread starter tshad
  • Start date Start date
T

tshad

I have a couple of issues here stemming from the same code.

I have a class that will sort a FileInfo array by date.

public class CompareFileInfoByDate : IComparer
{
public int Compare(object x, object y)
{
FileInfo File1 = default(FileInfo);
FileInfo File2 = default(FileInfo);

File1 = (FileInfo)x;
File2 = (FileInfo)y;

return DateTime.Compare(File1.LastWriteTime,
File2.LastWriteTime);
}
}

This works fine.

I call it like:

Array.Sort(strFiles, new CompareFileInfoByDate());

Where strFiles is an array of FileInfo objects.

This will sort by date in ascending order.

I pass it the class but not the method to use. How does it know what to
use.

The reason I am asking is that I need to sort this in ascending and
descending order.

One way around that is to just create another method exactly the same but
just reverse the return statement to look like:

return DateTime.Compare(File2.LastWriteTime,
File1.LastWriteTime);

This works fine.

Can I have another method in class that named - CompareReverse?

If so, how would I tell Array.Sort to use the CompareReverse?

I could write another whole class but it seems like overkill if I can just
use the same class for both methods.

I looked at Array.Reverse, but it won't take an IComparer interface.

Thanks,

Tom
 
I will try that.

What about the first part of the question?

In the class, can you only have one method that must be named Compare?

Thanks,

Tom
 
tshad said:
I will try that.

What about the first part of the question?

In the class, can you only have one method that must be named Compare?

Not at all, Tom. While if the class implements the IComparer interface it
must have one and only one Compare method, the class can have any other
methods or properties that you want.

Tom Dacon
Dacon Software Consulting
 
tshad said:
I have a class that will sort a FileInfo array by date.

public class CompareFileInfoByDate : IComparer
{
public int Compare(object x, object y)
{
File1 = (FileInfo)x;
File2 = (FileInfo)y;

return DateTime.Compare(File1.LastWriteTime,
File2.LastWriteTime);
}
}

This works fine.

I call it like:

Array.Sort(strFiles, new CompareFileInfoByDate());

Where strFiles is an array of FileInfo objects.

This will sort by date in ascending order.

I pass it the class but not the method to use. How does it know what to
use.

because you pass it an object that implements IComparer,
so it will call its Compare-method for all pairs of FileInfo within your
array, until it's sorted.
The reason I am asking is that I need to sort this in ascending and
descending order.
Can I have another method in class that named - CompareReverse?

Yes but it won't be called for sorting, since Array.Sort only will look
for and execute "IComparer.Compare" ignoring all the remaining methods
and members of the object.
A very good idea is, as Tom said, to pass a Ascending/Descending flag in
the c'tor and to evaluate it withing the Compare-call.

For example:

//call for descending sort
Array.Sort(strFiles, new CompareFileInfoByDate(true));

//class
public class CompareFileInfoByDate
{

private int _factor = 1;
public CompareFileInfoByDate (bool isDescending)
{
if (isDescending)
_factor = -1; /* this will reverse
the result of DateTime.Compare */
}
public int Compare(object x, object y)
{
File1 = (FileInfo)x;
File2 = (FileInfo)y;

return _factor * DateTime.Compare(File1.LastWriteTime,
File2.LastWriteTime);
}

}



Alex
 
tshad said:
I have a couple of issues here stemming from the same code.
Can I have another method in class that named - CompareReverse?

If so, how would I tell Array.Sort to use the CompareReverse?

One way would be to pass a value in to the constructor of your IComparer
that tells it which implementation method to use.

Perhaps an enum.

enum MYCOMPARE {LASTWRITE, REVERSE}

private MYCOMPARE comparetype
public int Compare(object x, object y)
{
FileInfo File1 = (FileInfo)x;
FileInfo File2= (FileInfo)y;

if(comparetype == MYCOMPARE.LASTWRITE)
return CompareLast(File1, File2);
else if (comparetype == MYCOMPARE.REVERSE)
return CompareReverse(File1, File2);
}

You could also use delegates

Sorry about the quick and dirty code...I am running late, but it should give
you enough to figure the rest out.

Bill
 
Tom Dacon said:
Not at all, Tom. While if the class implements the IComparer interface it
must have one and only one Compare method, the class can have any other
methods or properties that you want.
So then when I run:

Array.Sort(strFiles, new CompareFileInfoByDate());

It will instantiate the class (or actually since being passed with "new" in
the parameter it will instantiate automatically and pass the object to
Array) then it will call Compare (many times).

So I could not have a CompareReverse in there unless Compare called
CompareReverse based on a passed flag.

Now I wouldn't do that because I can just do an if test on a memory variable
and do 2 different returns.

The way I ended up doing it was (which was your suggestion):

public class CompareFileInfoByDate : IComparer
{
private bool mboolForward;

public CompareFileInfoByDate()
{
Forward = true;
}

public CompareFileInfoByDate(bool forward)
{
Forward = forward;
}

public int Compare(object x, object y)
{
FileInfo File1 = default(FileInfo);
FileInfo File2 = default(FileInfo);

File1 = (FileInfo)x;
File2 = (FileInfo)y;

if(Forward)
return DateTime.Compare(File1.LastWriteTime,
File2.LastWriteTime);
else
return DateTime.Compare(File2.LastWriteTime,
File1.LastWriteTime);
}

public bool Forward
{
get { return mboolForward; }
set { mboolForward = value; }
}

}

Thanks,

Tom
 
tshad said:
So then when I run:

Array.Sort(strFiles, new CompareFileInfoByDate());

It will instantiate the class (or actually since being passed with "new"
in the parameter it will instantiate automatically and pass the object to
Array) then it will call Compare (many times).

So I could not have a CompareReverse in there unless Compare called
CompareReverse based on a passed flag.

Now I wouldn't do that because I can just do an if test on a memory
variable and do 2 different returns.

The way I ended up doing it was (which was your suggestion):

public class CompareFileInfoByDate : IComparer
{
private bool mboolForward;

public CompareFileInfoByDate()
{
Forward = true;
}

public CompareFileInfoByDate(bool forward)
{
Forward = forward;
}

public int Compare(object x, object y)
{
FileInfo File1 = default(FileInfo);
FileInfo File2 = default(FileInfo);

File1 = (FileInfo)x;
File2 = (FileInfo)y;

if(Forward)
return DateTime.Compare(File1.LastWriteTime,
File2.LastWriteTime);
else
return DateTime.Compare(File2.LastWriteTime,
File1.LastWriteTime);
}

public bool Forward
{
get { return mboolForward; }
set { mboolForward = value; }
}

}

Thanks,

Tom

Just fine, Tom. The Forward property could just as well have been private,
the way you're using it, but it doesn't matter much.

Tom
 
Back
Top