Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Any way(s) to pass an IComparer object instance to ArrayList.sort?

123 views
Skip to first unread message

Sung M Kim

unread,
Nov 27, 2006, 1:10:08 PM11/27/06
to
Is there a way to implement an implement(say IComparer as the subject
says) in powershell and pass an instance of the impelemented class to
"arrayListObject.Sort( IComparer )" method?

I have been using built-in "CaseInsensitiveComparer" which implements
IComparer, but I would like to pass in my own comparison

Maximilian Hänel

unread,
Nov 27, 2006, 2:08:45 PM11/27/06
to
Hi Sung,

I don't think it's possible with PS because you can't create new types
(aka classes) with powershell at this time. You can of course create new
pseudo types (see PSCustomObject) but AFAICS you can't implement specfic
interfaces. What might be possible is to create a generic Comparer in C#
or whatever .NET language that actually does not compare but calls a
delegate via event mechanism. So theroetically it should then be
possible to write something like this:

$cmp=new-object "MyComparer"
$cmp.CompareCallback={Perform your comparison here}

arrayListObject.Sort( $cmp)

But I haven't tried this myself.

cu

Max

Maximilian Hänel

unread,
Nov 27, 2006, 3:34:10 PM11/27/06
to
Ok, so here's a quick hack of a "new-comparer" cmdlet. There's actually
no need for an event based callback as I thought first. We simply store
a "compare script" and call this each time ICompare.Compare() gets
called. By using this CmdLet you can write the following code (Note that
we access the objects to compare with $args[0] and $args[1]. The "return
value" must be of type int):

$a=ls
$cmp=new-Comparer {$args[0].Name.CompareTo($args[1].Name)}
[Array]::Sort($a, $cmp)

Please note however that in this case it's much easier to use the
sort-object:

ls | Sort Name

However, in case you have some very, very special needs, something like
a New-Comparer CmdLet might become handy. So here's the (not very well
tested) code:

//
namespace YourNamespace.Commands
{
using System;
using System.Management.Automation;
using System.Collections.ObjectModel;
using Microsoft.PowerShell.Commands;
using System.Collections.Generic;
using System.Collections;

[Cmdlet(VerbsCommon.New, "Comparer")]
public class NewComparerCommand:PSCmdlet
{
ScriptBlock m_CompareScript;

[Parameter(Mandatory=true, Position=0)]
public ScriptBlock CompareScript
{
get { return m_CompareScript; }
set { m_CompareScript=value; }
}

protected override void BeginProcessing()
{
WriteVerbose(String.Format("CompareScript: {0}",
CompareScript.ToString()));
WriteObject(new CustomComparer(CompareScript));
}
}

public sealed class CustomComparer:IComparer
{
ScriptBlock m_CompareScript;

public CustomComparer(ScriptBlock compareScript)
{
if(null==compareScript)
throw new ArgumentNullException("compareScript");

m_CompareScript=compareScript;
}

public ScriptBlock CompareScript
{
get { return m_CompareScript; }
set
{
if(null==value)
throw new ArgumentNullException("CompareScript");
m_CompareScript=value;
}
}

#region IComparer Members

public int Compare(object x, object y)
{
Collection<PSObject> res=CompareScript.Invoke(x,y);
return (int)(res[0].BaseObject);
}

#endregion
}
}
//eof

hth

Max

Sung M Kim

unread,
Nov 27, 2006, 3:39:58 PM11/27/06
to
thank you for the response there, Maximilian
The question was for an educational purpose only instead of using
Sort-Object cmdlet ;).

I guess I would have to look into your suggestion and using reflection
to create a custom type on the fly ~~~ ;)

Sung M Kim

unread,
Nov 27, 2006, 10:23:37 PM11/27/06
to

Maximilian Hänel wrote:

Thank you for providing the cmdlet source that I can play around with.
I did create a simple snapin and ...

> $a=ls
> $cmp=new-Comparer {$args[0].Name.CompareTo($args[1].Name)}
> [Array]::Sort($a, $cmp)

Ok, with the NewComparerCommand cmdlet,

$a = @("c", "b", "x", "z", "a", "e")
$cmp = new-comparer { $args[0].CompareTo($args[1]) }
[System.Array]::Sort($a, $cmp)
$a

Now displays:
a
b
c
e
x
z

And if i just simply changes the arg order,
>From "$args[0].CompareTo($args[1])" to "$args[1].CompareTo($args[0])"
$a is sorted as followed
z
x
e
c
b
a

It is working just as I expected and how I wanted the cmdlet to work ;)
Thanks~

> Please note however that in this case it's much easier to use the
> sort-object:
>
> ls | Sort Name

:-) Beh~ But it's not as fun as creating a cmdlet though ;)

0 new messages