Home All Groups Group Topic Archive Search About

Sorting Array using Icomparable

Author
17 Jun 2009 10:58 PM
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

Author
17 Jun 2009 11:16 PM
Tom Dacon
Show quote Hide quote
"tshad" <t***@pdsa.com> wrote in message
news:OcLjl857JHA.4132@TK2MSFTNGP06.phx.gbl...
>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
>

Consider giving your comparison class a constructor that takes a sort
direction argument. Save the direction value in a private field and test it
in the Compare function.

HTH,
Tom Dacon
Dacon Software Consulting
Are all your drivers up to date? click for free checkup

Author
18 Jun 2009 12:28 AM
tshad
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

Show quoteHide quote
"Tom Dacon" <tdacon@community.nospam> wrote in message
news:egJLhG67JHA.1416@TK2MSFTNGP04.phx.gbl...
>
> "tshad" <t***@pdsa.com> wrote in message
> news:OcLjl857JHA.4132@TK2MSFTNGP06.phx.gbl...
>>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
>>
>
> Consider giving your comparison class a constructor that takes a sort
> direction argument. Save the direction value in a private field and test
> it in the Compare function.
>
> HTH,
> Tom Dacon
> Dacon Software Consulting
>
Author
18 Jun 2009 12:42 AM
Tom Dacon
"tshad" <t***@pdsa.com> wrote in message
news:OYfdlu67JHA.4116@TK2MSFTNGP04.phx.gbl...
>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
Author
18 Jun 2009 5:09 PM
tshad
Show quote Hide quote
"Tom Dacon" <tdacon@community.nospam> wrote in message
news:ua742267JHA.5932@TK2MSFTNGP03.phx.gbl...
>
> "tshad" <t***@pdsa.com> wrote in message
> news:OYfdlu67JHA.4116@TK2MSFTNGP04.phx.gbl...
>>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.
>
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
Show quoteHide quote
> Tom Dacon
> Dacon Software Consulting
>
>
Author
19 Jun 2009 12:09 AM
Tom Dacon
Show quote Hide quote
"tshad" <t***@pdsa.com> wrote in message
news:%23s9T$dD8JHA.728@TK2MSFTNGP05.phx.gbl...
>
> "Tom Dacon" <tdacon@community.nospam> wrote in message
> news:ua742267JHA.5932@TK2MSFTNGP03.phx.gbl...
>>
>> "tshad" <t***@pdsa.com> wrote in message
>> news:OYfdlu67JHA.4116@TK2MSFTNGP04.phx.gbl...
>>>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.
>>
> 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
>> Tom Dacon
>> Dacon Software Consulting
>>
>>
>
>

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
Author
18 Jun 2009 1:23 AM
Peter Duniho
On Wed, 17 Jun 2009 15:58:34 -0700, tshad <t***@pdsa.com> wrote:

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

Because it uses the IComparer implementation, and that method is the 
implementation.

> 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?

Sure.  You can put whatever methods into the class you want.  But it won't 
be used in the comparison.

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

You don't.  It can only call Compare(), because that's the one method in 
IComparer and the IComparer implementation is the only thing Array.Sort() 
cares about.

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

Seems to me the simplest approach is to use a multiplier in the class, and 
then initialize the class appropriate, depending on whether you want it to 
do ascending or descending:

     public class CompareFileInfoByDate : IComparer
     {
         public CompareFileInfoByDate(bool fAscending)
         {
             _faction = fAscending ? 1 : -1;
         }

         private int _factor;

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

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

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

Why would it?  All it does is reverse the existing contents, whether they 
are sorted or not.

You could, of course, always sort ascending, and then reverse the results 
if you want descending.  But it's more efficient to just sort in the order 
you want.

Pete
Author
18 Jun 2009 12:13 PM
Alexander Mueller
tshad schrieb:

Show quoteHide quote
> 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
Author
18 Jun 2009 12:33 PM
Bill Butler
"tshad" <t***@pdsa.com> wrote in message
news:OcLjl857JHA.4132@TK2MSFTNGP06.phx.gbl...
>I have a couple of issues here stemming from the same code.
>
<snip>
>
> 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

Bookmark and Share