问题
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 interfaceIComparable
. That means yourArrayList
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.
- They're not type-safe, and
- 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