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

时间:2015-04-16 14:43:04

标签: java arrays sorting

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

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类型创建的,因此我可以按多种类型排序(不仅仅是示例中的字符串)。

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

4 个答案:

答案 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接口的嵌套类来创建比较器。

例如,这是一个单ComparatorCar实例与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)

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

答案 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()。 : - )

总的来说,这种方法应该可以提高代码的效率。 }