java按可指定属性排序对象列表

我想按这些对象的指定属性对对象列表进行排序,我想选择应该用于排序的属性。 例:

class Car{ private String name; private String colour; public enum sortBy {NAME, COLOUR}; public String name(){ return name; } public String colour(){ return colour; } public static Car[] getSortedArray(Car[] carArray, sortBy sortType){ HashMap carMap = new HashMap(); Object[] sortArray = new Object[carArray.length]; Object value = null; for(int i = 0; i < carArray.length; i++){ if(sortType == sortBy.NAME){ value = carArray[i].name(); }else if(sortType == sortBy.COLOUR){ value = carArray[i].colour(); } carMap.put(value, carArray[i]); sortArray[i] = value; } Arrays.sort(sortArray); Car[] sortedArray = new Car[sortArray.length]; for(int i = 0; i < sortArray.length; i++){ sortedArray[i] = carMap.get(sortArray[i]); } return sortedArray; } } //external: Car[] cars = getSomeCars(); Car[] nameSortedCars = Car.getSortedArray(cars, Car.sortBy.NAME); Car[] colourSortedCars = Car.getSortedArray(cars, Car.sortBy.COLOUR); 

这个想法很简单:
我将所有想要排序的值放入一个数组中,然后创建一个将这些值映射回其对象的映射。 在我对这个数组进行排序之后,我将映射到这些值的对象放在一个新的数组中,然后按这些值排序。 这些值只是使用Object类型创建的,因此我可以按多种类型排序(不仅仅是示例中的字符串)。

除非你有两个具有相同属性值的对象,否则只有一个对象将在返回的数组中,但是两次。
有没有更好的方法来实现这种排序?

使用自定义比较器会简单得多:

name排序:

 Arrays.sort(carArray, Comparator.comparing(Car::name)); 

colour排序:

 Arrays.sort(carArray, Comparator.comparing(Car::colour)); 

所以你可以修改getSortedArray()

 public static Car[] getSortedArray(Car[] carArray, Comparator comparator) { Car[] sorted = carArray.clone() Arrays.sort(sorted, comparator); return sorted; } 

并称之为:

 Car[] sorted = getSortedArray(carArray, Comparator.comparing(Car::name)); 

编辑:

如果使用不支持这些function的语言版本,则可以通过显式创建实现Comparator接口的嵌套类来创建Comparator器。

例如,这是一个单例Comparator ,它按name比较Car实例:

 static enum ByName implements Comparator { INSTANCE; @Override public int compare(Car c1, Car c2) { return c1.name().compareTo(c2.name()); } } 

然后打电话:

 Car[] sorted = getSortedArray(carArray, ByName.INSTANCE); 

TL; DR:已经有了一个轮子。

我想说最简单的方法是创建一个比较器:

 final Comparator byName = Comparator.comparing(Car::name); final Comparator byColour = Comparator.comparing(Car::colour); 

然后在Arrays上使用适当的方法按比较器排序:

 Arrays.sort(carArray, byName); 

现在你想用enum做吗? 只需让enum implements Comparator

 enum SortBy implements Comparator { NAME(Comparator.comparing(Car::name)), COLOUR(Comparator.comparing(Car::colour)); private final Comparator delegate; private SortBy(Comparator delegate) { this.delegate = delegate; } @Override public int compare(final Car o1, final Car o2) { return delegate.compare(o1, o2); } } 

想按name排序, 然后按 colour排序? 简单:

 final Comparator byName = SortBy.NAME.thenComparing(SortBy.COLOUR); 

想按相反的顺序按名称排序 ? 简单:

 final Comparator byName = SortBy.NAME.reversed(); 

你正在重新发明轮子! 如果您使用模板化的Collections API,生活将变得更加容易。 为此,您将使用List而不是数组,定义Comparator来进行排序,然后让API为您完成工作。

  Comparator carComparator = new Comparator(){ public int sort(Car car1, Car car2){ //Sorting logic goes here. } } List cars = getCars(); cars = Collections.sort(cars, carComparator); //the cars collection is now sorted. 

如果您希望有时按一个属性或另一个属性排序,可以将我的变量carComparator放入其自己的类中,并在构造函数中定义要排序的属性。

希望有所帮助:)

编辑:正如其他人所指出的,这种方法也适用于数组。 但除非你有充分的理由使用Arrays,否则使用Collections通常会更容易。

我认为如果将Comparator实现传递给Arrays.sort,解决方案会更有效。 现在,你从它的外观循环n * 2,哈希映射(O(1))加上Arrays.sort(这是另一个0(n log n)等)。 如果您执行以下操作,则可以跳过当前正在使用的2个循环和地图。

你可以简单地创建一个像(粗略代码)的比较器:

 class CarComparator implements Comparator { enum compareType; //plus setter public int compareTo(Car a, Car b) { if(compareType == COLOUR) return a.colour.compareTo(b.colour); if(compareType == NAME..... } } 

,然后简单地发送汽车数组

 Arrays.sort(cars, new CarComparator(COLOUR)) 

,或使用更专业的比较器类,每个属性一个,以及渲染它们的工厂,当然,如果经常发生这种情况,不要为每种类型创建新的Comparator()。 🙂

总的来说,这种方法应该使您的代码更有效。 }