about IComparer and Comparer

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • Tony

    about IComparer and Comparer

    Hello!

    I'm reading in a book and this can't be correct it says.
    "Objects passed to Comparer.Compar e() are checked to see if they support
    IComparable.
    If they do, then that implementation is used"

    Assume I have a collection of Item(s) in an ArrayList
    This class called Item support the IComparable interface which contains the
    CompareTo method
    so this method is impemented in class Item.

    Now I can sort in the way that this CompareTo is implemented.

    Now assume I want to be able to sort the collection of item(s) in another
    way then this CompareTo is implementet
    so I create an helper class which implement the IComparer interface which
    contains method Compare.

    So not to my question when object of type Item is passed to the Compare
    method that implementation
    is used of course not the implementation that exist for the IComparable.

    //Tony


  • Marc Gravell

    #2
    Re: about IComparer and Comparer

    ArrayList.Sort has several overloads; the parameterless one uses
    Comparer.Defaul t, which (as you discussed) will use the objects
    IComparable support (if any). If you want a custom sort, there is an
    overload (2, actually) that accepts your custom IComparer, in which
    case Comparer.Defaul t is *not* used.

    Note that in .NET 2.0, it would be better to consider List<T>,
    IComparer<T>, IComparable<Tan d Comparer<T>.Def ault.

    Marc

    Comment

    • Jon Skeet [C# MVP]

      #3
      Re: about IComparer and Comparer

      On Jun 17, 9:18 am, "Tony" <johansson.ande rs...@telia.com wrote:
      I'm reading in a book and this can't be correct it says.
      "Objects passed to Comparer.Compar e() are checked to see if they support
      IComparable.
      If they do, then that implementation is used"
      One thing to note is that most of the time you should now be using the
      generic Comparer<Tclass and in particular Comparer<T>.Def ault.
      Assume I have a collection of Item(s) in an ArrayList
      This class called Item support the IComparable interface which contains the
      CompareTo method
      so this method is impemented in class Item.
      >
      Now I can sort in the way that this CompareTo is implemented.
      >
      Now assume I want to be able to sort the collection of item(s) in another
      way then this CompareTo is implementet
      so I create an helper class which implement the IComparer interface which
      contains method Compare.
      So far so good - but at that point you don't use the Comparer class,
      you just pass an instance of your IComparer implementation into
      whatever sorting method you're using.
      So not to my question when object of type Item is passed to the Compare
      method that implementation
      is used of course not the implementation that exist for the IComparable.
      The quote you gave specified part of the implementation of
      Comparer.Compar e. If you're not calling Comparer.Compar e, then the
      quote is irrelevant. Why would you call Comparer.Compar e if you want
      to use a custom IComparer implementation?

      Perhaps it would help if you'd provide a short but complete example,
      and ask what the behaviour is and why for a specific method call.

      Jon

      Comment

      • Tony

        #4
        Re: about IComparer and Comparer

        Here I have not Complete program enough to be able to answer my question.
        Here again I pass an object to this Comparer.Compar e() although there is an
        Default in between.
        >Objects passed to Comparer.Compar e() are checked to see if they support
        IComparable.
        If they do, then that implementation is used"
        Below when I pass object to this Comparer.Defaul t.Compare I don't use the
        implementation from
        IComparable that the text above is claiming I use whatever relevent code I
        want.?

        So what the text is claiming must be completely nonsens.!

        public class Item : IComparable
        {
        private int steelGrade;
        private int heatNumber;
        private string mspName;
        private string dateTime;
        private int optTime;
        private ArrayList listOpt;
        private ArrayList listDateTime;

        public ArrayList ListDateTime
        {
        set { listDateTime = value; }
        get { return listDateTime; }
        }

        public ArrayList ListOpt
        {
        set {listOpt = value; }
        get { return listOpt; }
        }

        public int OptTime
        {
        set { optTime = value; }
        get { return optTime; }
        }

        public string DateTime
        {
        set { dateTime = value; }
        get { return dateTime; }
        }

        public int Steelgrade
        {
        set { steelGrade = value; }
        get { return steelGrade; }
        }

        public int HeatNumber
        {
        set { heatNumber = value; }
        get { return heatNumber; }
        }

        public string MspName
        {
        set { mspName = value; }
        get { return mspName; }
        }

        public int CompareTo(objec t right)
        {
        if (right is Item)
        {
        Item item = right as Item;
        if (this.HeatNumbe r != item.HeatNumber )
        return this.HeatNumber .CompareTo(item .HeatNumber);
        else
        return this.MspName.Co mpareTo(item.Ms pName);
        }
        else
        throw new ArgumentExcepti on("Object to compare is not a Item
        object");

        }
        }


        public class ItemComparer : IComparer
        {
        public static IComparer Default = new ItemComparer();

        public int Compare(object left, object right)
        {
        if (left is Item && right is Item)
        {
        if (((Item)left).S teelgrade != ((Item)right).S teelgrade)
        return Comparer.Defaul t.Compare(
        ((Item)left).St eelgrade, ((Item)right).S teelgrade);
        else
        return Comparer.Defaul t.Compare(
        ((Item)left).Ms pName, ((Item)right).M spName);
        }
        else
        throw new ArgumentExcepti on("One of the object is not an
        Item");
        }
        }

        //Tony


        "Jon Skeet [C# MVP]" <skeet@pobox.co mskrev i meddelandet
        news:cc382fa6-b9d6-4d7f-a2fc-e15a92962b3a@27 g2000hsf.google groups.com...
        On Jun 17, 9:18 am, "Tony" <johansson.ande rs...@telia.com wrote:
        I'm reading in a book and this can't be correct it says.
        "Objects passed to Comparer.Compar e() are checked to see if they support
        IComparable.
        If they do, then that implementation is used"
        >
        One thing to note is that most of the time you should now be using the
        generic Comparer<Tclass and in particular Comparer<T>.Def ault.
        >
        Assume I have a collection of Item(s) in an ArrayList
        This class called Item support the IComparable interface which contains
        the
        CompareTo method
        so this method is impemented in class Item.

        Now I can sort in the way that this CompareTo is implemented.

        Now assume I want to be able to sort the collection of item(s) in
        another
        way then this CompareTo is implementet
        so I create an helper class which implement the IComparer interface
        which
        contains method Compare.
        >
        So far so good - but at that point you don't use the Comparer class,
        you just pass an instance of your IComparer implementation into
        whatever sorting method you're using.
        >
        So not to my question when object of type Item is passed to the Compare
        method that implementation
        is used of course not the implementation that exist for the IComparable.
        >
        The quote you gave specified part of the implementation of
        Comparer.Compar e. If you're not calling Comparer.Compar e, then the
        quote is irrelevant. Why would you call Comparer.Compar e if you want
        to use a custom IComparer implementation?
        >
        Perhaps it would help if you'd provide a short but complete example,
        and ask what the behaviour is and why for a specific method call.
        >
        Jon

        Comment

        • Marc Gravell

          #5
          Re: about IComparer and Comparer

          That is *not* a complete program; it has no "Main", so does nothing
          (not even compile...).

          Re your question - the only things you pass to
          Comparer.Defaul t.Compare(...) are two ints (the two Steelgrade
          properties); I fully expect that Comparer will give the correct answer
          for comparing two ints, but there is no reason to expect it to call
          your IComparable implementation - it isn't comparing Item, it is
          comparing ints - it will use the Int32.Compare method.

          Marc

          Comment

          • Marc Gravell

            #6
            Re: about IComparer and Comparer

            (white lie - you also pass two strings, but this will behave similarly)

            Comment

            • Jon Skeet [C# MVP]

              #7
              Re: about IComparer and Comparer

              On Jun 17, 10:04 am, "Tony" <johansson.ande rs...@telia.com wrote:
              Here I have not Complete program enough to be able to answer my question.
              Here again I pass an object to this Comparer.Compar e() although there is an
              Default in between.
              Well, your code is really making things confusing by having an
              ItemComparer.De fault as well as using Comparer.Defaul t.
              Objects passed to Comparer.Compar e() are checked to see if they support
              IComparable.
              If they do, then that implementation is used"
              >
              Below when I pass object to this Comparer.Defaul t.Compare I don't use the
              implementation from
              IComparable that the text above is claiming I use whatever relevent code I
              want.?
              The call to Comparer.Defaul t.Compare with the two different Steelgrade
              values will use the fact that int implements IComparable. That's all
              that the text is claiming. The rest of your code isn't a call to
              Comparer.Compar e, it's an implementation of IComparer.Compa re. There's
              a huge difference.

              Mind you, your code would be significantly simpler if you just called
              Compare directly, preferrably avoiding all those casts:

              public int Compare(object left, object right)
              {
              // TODO: optimise for left == right, and consider cases
              // where one side or other is null
              Item leftItem = left as Item;
              Item rightItem = right as Item;
              if (leftItem == null || rightItem == null)
              {
              throw new ArgumentExcepti on("One of the objects is not an
              Item");
              }
              if (leftItem.Steel grade != rightItem.Steel grade)
              {
              return leftItem.Steelg rade.CompareTo( rightItem.Steel grade);
              }
              // TODO: Consider what kind of string comparison you want (culture/
              ordinal/case sensitive)
              return leftItem.MspNam e.CompareTo(rig htItem.MspName) ;
              }
              So what the text is claiming must be completely nonsens.!
              No it's not. Comparer.Compar e will use the IComparable.Com pareTo
              implementation. But other implementations of IComparer are free to do
              what they want.

              It seems to me that you're not distinguishing between the interface
              (IComparer) and *one* implementation (Comparer).

              Jon

              Comment

              • Marc Gravell

                #8
                Re: about IComparer and Comparer

                Here's a Main that demonstrates it working just fine... you'll have to
                forgive some C# 3 initializer syntax (easy enough to see what it does,
                though):

                class Program
                {
                static void Main()
                {
                ArrayList list = new ArrayList();
                list.Add(new Item { HeatNumber = 1, Steelgrade = 4, MspName =
                "def" });
                list.Add(new Item { HeatNumber = 3, Steelgrade = 4, MspName =
                "ghi" });
                list.Add(new Item { HeatNumber = 1, Steelgrade = 2, MspName =
                "abc" });
                list.Add(new Item { HeatNumber = 2, Steelgrade = 1, MspName =
                "jkl" });
                Console.WriteLi ne("Using custom sort (HeatNumber, MspName)");
                list.Sort();
                foreach (Item item in list)
                {
                Console.WriteLi ne("{0}: hn: {1}, sg: {2}", item.MspName,
                item.HeatNumber , item.Steelgrade );
                }
                Console.WriteLi ne("Using custom sort (Steelgrade, MspName)");
                list.Sort(ItemC omparer.Default );
                foreach (Item item in list)
                {
                Console.WriteLi ne("{0}: hn: {1}, sg: {2}", item.MspName,
                item.HeatNumber , item.Steelgrade );
                }
                }
                }

                Comment

                • Marc Gravell

                  #9
                  Re: about IComparer and Comparer

                  (sorry, copy/paste - first is the default sort using the item's
                  IComparable implementation)

                  Comment

                  • Tony

                    #10
                    Re: about IComparer and Comparer

                    Hello!

                    You say that your code would be significantly simpler if you just called
                    Compare directly, preferrably avoiding all those casts:
                    You you mean as the code prove instead CompareTo(...) I assume

                    //Tony



                    "Jon Skeet [C# MVP]" <skeet@pobox.co mskrev i meddelandet
                    news:804d9000-c7c9-45e3-9a29-841d22a6ec1e@s5 0g2000hsb.googl egroups.com...
                    On Jun 17, 10:04 am, "Tony" <johansson.ande rs...@telia.com wrote:
                    Here I have not Complete program enough to be able to answer my
                    question.
                    Here again I pass an object to this Comparer.Compar e() although there is
                    an
                    Default in between.
                    >
                    Well, your code is really making things confusing by having an
                    ItemComparer.De fault as well as using Comparer.Defaul t.
                    >
                    >Objects passed to Comparer.Compar e() are checked to see if they
                    support
                    IComparable.
                    If they do, then that implementation is used"
                    Below when I pass object to this Comparer.Defaul t.Compare I don't use
                    the
                    implementation from
                    IComparable that the text above is claiming I use whatever relevent code
                    I
                    want.?
                    >
                    The call to Comparer.Defaul t.Compare with the two different Steelgrade
                    values will use the fact that int implements IComparable. That's all
                    that the text is claiming. The rest of your code isn't a call to
                    Comparer.Compar e, it's an implementation of IComparer.Compa re. There's
                    a huge difference.
                    >
                    Mind you, your code would be significantly simpler if you just called
                    Compare directly, preferrably avoiding all those casts:
                    >
                    public int Compare(object left, object right)
                    {
                    // TODO: optimise for left == right, and consider cases
                    // where one side or other is null
                    Item leftItem = left as Item;
                    Item rightItem = right as Item;
                    if (leftItem == null || rightItem == null)
                    {
                    throw new ArgumentExcepti on("One of the objects is not an
                    Item");
                    }
                    if (leftItem.Steel grade != rightItem.Steel grade)
                    {
                    return leftItem.Steelg rade.CompareTo( rightItem.Steel grade);
                    }
                    // TODO: Consider what kind of string comparison you want (culture/
                    ordinal/case sensitive)
                    return leftItem.MspNam e.CompareTo(rig htItem.MspName) ;
                    }
                    >
                    So what the text is claiming must be completely nonsens.!
                    >
                    No it's not. Comparer.Compar e will use the IComparable.Com pareTo
                    implementation. But other implementations of IComparer are free to do
                    what they want.
                    >
                    It seems to me that you're not distinguishing between the interface
                    (IComparer) and *one* implementation (Comparer).
                    >
                    Jon

                    Comment

                    • Jon Skeet [C# MVP]

                      #11
                      Re: about IComparer and Comparer

                      On Jun 17, 11:17 am, "Tony" <johansson.ande rs...@telia.com wrote:
                      You say that your code would be significantly simpler if you just called
                      Compare directly, preferrably avoiding all those casts:
                      You you mean as the code prove instead CompareTo(...) I assume
                      Sorry, yes, I meant CompareTo.

                      Jon

                      Comment

                      Working...