我想按照这些对象的指定属性对对象列表进行排序,我想选择应该用于排序的属性。示例:
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<Object, Car> carMap = new HashMap<Object, Car>();
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类型创建的,因此我可以按多种类型排序(不仅仅是示例中的字符串)。
除非你有两个具有相同属性值的对象,否则这个工作正常,那么只有一个对象将在返回的数组中,但是两次。
有没有更好的方法来实现这种排序?
答案 0 :(得分:6)
使用自定义比较器会更简单:
按name
排序:
Arrays.sort(carArray, Comparator.comparing(Car::name));
按colour
排序:
Arrays.sort(carArray, Comparator.comparing(Car::colour));
所以你可以修改getSortedArray()
:
public static Car[] getSortedArray(Car[] carArray, Comparator<Car> comparator) {
Car[] sorted = carArray.clone()
Arrays.sort(sorted, comparator);
return sorted;
}
并称之为:
Car[] sorted = getSortedArray(carArray, Comparator.comparing(Car::name));
修改强>
如果使用不支持这些功能的语言版本,则可以通过显式创建实现Comparator
接口的嵌套类来创建比较器。
例如,这是一个单Comparator
个Car
实例与name
进行比较:
static enum ByName implements Comparator<Car> {
INSTANCE;
@Override
public int compare(Car c1, Car c2) {
return c1.name().compareTo(c2.name());
}
}
然后致电:
Car[] sorted = getSortedArray(carArray, ByName.INSTANCE);
答案 1 :(得分:2)
我想说最简单的方法是创建一个比较器:
final Comparator<Car> byName = Comparator.comparing(Car::name);
final Comparator<Car> byColour = Comparator.comparing(Car::colour);
然后在Arrays
上使用适当的方法按比较器排序:
Arrays.sort(carArray, byName);
现在你想用enum
来做?只需拥有enum
implements Comparator<Car>
:
enum SortBy implements Comparator<Car> {
NAME(Comparator.comparing(Car::name)),
COLOUR(Comparator.comparing(Car::colour));
private final Comparator<Car> delegate;
private SortBy(Comparator<Car> delegate) {
this.delegate = delegate;
}
@Override
public int compare(final Car o1, final Car o2) {
return delegate.compare(o1, o2);
}
}
想要按name
排序,然后按 colour
排序?易:
final Comparator<Car> byName = SortBy.NAME.thenComparing(SortBy.COLOUR);
想要按逆序按名称排序?易:
final Comparator<Car> byName = SortBy.NAME.reversed();
答案 2 :(得分:0)
你正在重新发明轮子!如果您使用模板化的Collections API,生活将变得更加容易。为此,您将使用List而不是数组,定义Comparator进行排序,然后让API为您完成工作。
Comparator<Car> carComparator = new Comparator<Car>(){
public int sort(Car car1, Car car2){
//Sorting logic goes here.
}
}
List<Car> cars = getCars();
cars = Collections.sort(cars, carComparator); //the cars collection is now sorted.
如果您希望有时按一个属性或另一个属性排序,可以将我的变量carComparator放入其自己的类中,并在构造函数中定义要排序的属性。
希望有所帮助:)
编辑:正如其他人所指出的,这种方法也适用于数组。但除非你有充分的理由使用Arrays,否则使用Collections通常会更容易。
答案 3 :(得分:0)
我认为如果将Comparator实现传递给Arrays.sort,解决方案会更有效。现在,你从它的外观,哈希映射(O(1))加上Arrays.sort(它是另一个0(n log n)等)循环n * 2。如果您执行以下操作,则可以跳过当前使用的2个循环和地图。
你可以简单地创建一个类似(粗略代码)的比较器:
class CarComparator implements Comparator<Car> {
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()。 : - )
总的来说,这种方法应该可以提高代码的效率。 }