Sort ArrayList with two dimensional objects

落花浮王杯 提交于 2021-01-28 21:07:10

问题


I have an ArrayList where I store 10 objects with two random generated numbers each and I want to sort the list by the Y values of the objects.

Random rndm = new Random();
ArrayList CustomList = new ArrayList();

for (int i = 0; i < 10; i++) 
{
    Point LP = new Point(rndm.Next(50), rndm.Next(50));
    CustomList.Add(LP); 
}

PrintList(CustomList);
CustomList.Sort(); 
PrintList(CustomList);

The Sort method throws the following exception:

System.InvalidOperationException: The comparer threw an exception. ---> System.ArgumentException: At least one object must implement IComparable.

I assume it doesn't work because the Sort method can not handle two dimensional objects in the ArrayLists. How can I get the Sort method to work now?


回答1:


ArrayList CustomList = new ArrayList();

is just a one dimensional list - the fact that a Point has two dimensions has nothing to do with the dimensionality of the list. A two-dimensional array of Points (Point[][]) would look like this:

row col1  col2  col3
1   Point Point Point
2   Point Point Point
3   Point Point Point

The problem is that Point does not implement the IComparable interface by default. This makes sense - can you tell if (1, 3) is greater than or smaller than (2, 2)? If you compare by first coordinate, it is smaller, but if you compare by distance to origin, it is greater.

Now that you have decided which comparison function you want to use, you can create a new PointComparer class:

public class PointComparer : IComparer<Point> {
    // return -1 if x is the smallest, 1 if y is the smallest, 0 if they're equal
    public int Compare(Point x, Point y) {
        return x.Y.CompareTo(y.Y);
    }
}

declare your CustomList as

List<Point> CustomList = new List<Point>();

and sort it with

CustomList.Sort(new PointComparer());



回答2:


The best way would be to use List<Point>, still even with ArrayList you can use LINQ:

Random rndm = new Random();
ArrayList CustomList = new ArrayList();

for (int i = 0; i < 10; i++) 
{
  Point LP = new Point(rndm.Next(50), rndm.Next(50));
  CustomList.Add(LP); 
}

var sorted = CustomList.Cast<Point>()
                        .OrderBy(p => p.Y)
                        .ToList();

If you want to have ArrayList as a returned structure:

ArrayList sortedAL = new ArrayList(sorted);



回答3:


The original poster said:

The Sort method throws the following exception:

System.InvalidOperationException: The comparer threw an exception. --->
   System.ArgumentException: At least one object must implement IComparable.

I assume it doesn't work because the Sort method can not handle two dimensional ArrayLists.

You are confused on two points:

  • First, it doesn't work because of what the exception message told you: the Point class doesn't implement the interface IComparable. That means your ArrayList doesn't know how to compare two points:

How does Point(1,2) compare to Point(2,1: is the first greater than, less than or equal to the second?

  • Second, ArrayList is just an array -- a list -- of objects. It is inherently 1-dimensional. It is an adjustable length equivalent of, say, object[].

  • Third, you should avoid using the non-generic collection classes, for a couple of reasons.

    1. They're not type-safe, and
    2. The generic versions are a whole lot easier to use since they're strongly typed: you don't have to downcast the contained references into the correct type.

So, given this definition of Point:

public struct Point
{
  public int X { get ; set ; }
  public int Y { get ; set ; }

  public Point( int x , int y )
  {
     this.X = x ;
     this.Y = y ;
  }
}

You could sort your ArrayList thusly:

public class PointComparer : IComparer
{
  int IComparer.Compare( object x , object y )
  {
    if ( x != null && !(x is Point) ) throw new ArgumentException();
    if ( y != null && !(y is Point) ) throw new ArgumentException();

    if      ( x == null && y == null ) return  0 ; // two nulls are equals
    else if ( x == null && y != null ) return -1 ; // we're collating nulls-low: change to +1 to collate nulls-high
    else if ( x != null && y == null ) return +1 ; // we're collating nulls-low: change to -1 to collate nulls-high
    else // both x and y are non-null
    {
      Point left  = (Point) x ;
      Point right = (Point) y ;

      if ( left.Y <  right.Y ) return -1 ;
      else if ( left.Y >  right.Y ) return +1 ;
      else // ( left.Y == right.Y )
      {
        if      ( left.X  < right.X )    return -1 ;
        else if ( left.X  > right.X )    return +1 ;
        else /* ( left.X == right.X ) */ return  0 ;
      }

    }
  }
}

...

ArrayList listOfPoints = CreateListofPoints();
listOfPoints.Sort( new PointComparer() ) ;

Or you could use the generic collections and accomplish the same thing a whole lot more concisely:

List<Point> listOfPoints = CreateListOfPoints();
listOfPoints.Sort( (left,right) => left.Y.CompareTo(right.Y) != 0
                                 ? left.Y.CompareTo(right.Y )
                                 : left.X.CompareTo(right.X)
) ;


来源:https://stackoverflow.com/questions/32235684/sort-arraylist-with-two-dimensional-objects

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!