用二维对象排序数组列表

本文关键字:对象 排序 数组 列表 二维 | 更新日期: 2023-09-27 18:09:55

我有一个ArrayList,其中我存储了10个对象,每个对象随机生成两个数字,我想按对象的Y值对列表进行排序。

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);

Sort方法抛出以下异常:

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

我认为它不起作用,因为Sort方法不能处理数组列表中的二维对象。我怎样才能使排序方法现在工作?

用二维对象排序数组列表

ArrayList CustomList = new ArrayList();

只是一个一维列表——Point具有二维的事实与列表的维度无关。点的二维数组(Point[][])看起来像这样:

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

问题是Point默认不实现IComparable接口。这是有意义的-你能分辨出(1,3)是大于还是小于(2,2)吗?如果按第一个坐标比较,它会更小,但如果按到原点的距离比较,它会更大。

现在您已经决定了要使用哪个比较函数,您可以创建一个新的PointComparer类:
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);
    }
}

声明你的CustomList

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

,用

排序
CustomList.Sort(new PointComparer());

最好的方法是使用List<Point>,即使使用ArrayList,您也可以使用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();

如果您想将ArrayList作为返回结构:

ArrayList sortedAL = new ArrayList(sorted);

原海报上写着:

Sort方法抛出以下异常:
System.InvalidOperationException: The comparer threw an exception. --->
   System.ArgumentException: At least one object must implement IComparable.

我认为它不起作用,因为Sort方法不能处理两个维ArrayLists。

你混淆了两点:

    首先,它不能工作是因为异常消息告诉你的: Point类没有实现接口IComparable。这意味着你的ArrayList不知道如何比较两点:

Point(1,2)Point(2,1比较:第一个大于、小于或等于第二个?

  • 第二,ArrayList只是一个数组——一个对象列表。它本身就是一维的。它是一个可调整的长度,相当于object[]

  • 第三,出于以下几个原因,您应该避免使用非泛型集合类。

      它们不是类型安全的,并且
  • 泛型版本更容易使用,因为它们是强类型的:你不必将包含的引用向下转换为正确的类型。

那么,给定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 ;
  }
}

你可以这样排序你的ArrayList:

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() ) ;

或者您可以使用泛型集合来更简洁地完成相同的事情:

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