java按可指定属性对对象列表进行排序
Posted
技术标签:
【中文标题】java按可指定属性对对象列表进行排序【英文标题】:java sort list of objects by specifiable attribute 【发布时间】:2015-06-23 01:32:21 【问题描述】:我想按对象的指定属性对对象列表进行排序,并且我想选择应该使用哪个属性进行排序。示例:
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 类型创建的,所以我可以按多种类型排序(不仅仅是示例中的字符串)。
这很好用,除非您有两个具有相同属性值的对象,那么返回的数组中只会有一个对象,但会出现两次。 有没有更好的方法来实现这种排序?
【问题讨论】:
问题是,HashMap 不接受重复的键,那么如果你有 2 个具有相同键的对象,第二个会超速第一个。 【参考方案1】:使用自定义比较器会简单得多:
按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);
【讨论】:
这看起来可以解决我的问题,但它似乎不适用于 android。我将 Java 8 用作 AndroidStudio 的 JDK,但它似乎不知道 Comparator.comparing 和 Car::name 给我一个错误,即此语言级别不支持方法引用。 @jklmnn 我更新了答案。这应该适用于较旧的 Java 版本。 好的,这似乎是一个 Android 问题,我用汽车类创建了一个小测试,并且有效。谢谢!【参考方案2】:TL;DR:已经有***了。
我想说最简单的方法是创建一个比较器:
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();
【讨论】:
【参考方案3】:您正在重新发明***!如果你使用模板化的 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 放入它自己的类中,并在构造函数中定义要按哪些属性排序。
希望有帮助:)
编辑:正如其他人指出的那样,这种方法也适用于数组。但除非您有充分的理由使用数组,否则使用集合通常会更容易。
【讨论】:
【参考方案4】:我认为如果您将 Comparator 实现传递给 Arrays.sort,该解决方案会更有效。现在,从外观上看,您正在循环 n*2,哈希映射 (O(1)) 加上 Arrays.sort (另一个 0(n log n) 等)。如果您执行以下操作,您可以跳过当前使用的 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.....
,然后简单地将 Cars 数组发送到
Arrays.sort(cars, new CarComparator(COLOUR))
,或者使用更专业的比较器类,一个用于每个属性,一个工厂来渲染它们,当然如果这种情况经常发生,不要为每个排序创建一个新的 Comparator()。 :-)
总体而言,这种方法应该使您的代码更有效率。
【讨论】:
以上是关于java按可指定属性对对象列表进行排序的主要内容,如果未能解决你的问题,请参考以下文章