如何在不同的时间通过不同的参数对列表进行sorting

我有一个名为Person具有多个属性的类,例如:

 public class Person { private int id; private String name, address; // Many more properties. } 

很多Person对象存储在ArrayList<Person> 。 我想通过多个sorting参数对这个列表进行sorting,而且时常不同。 例如,我可能有一次想按name升序sorting,然后address降序,而另一次只是由id降序。

我不想创build我自己的sorting方法(即,我想使用Collections.sort(personList, someComparator) 。什么是最优雅的解决scheme,实现这一点?

我认为你的枚举方法基本上是合理的,但是switch语句确实需要一个更加面向对象的方法。 考虑:

 enum PersonComparator implements Comparator<Person> { ID_SORT { public int compare(Person o1, Person o2) { return Integer.valueOf(o1.getId()).compareTo(o2.getId()); }}, NAME_SORT { public int compare(Person o1, Person o2) { return o1.getFullName().compareTo(o2.getFullName()); }}; public static Comparator<Person> decending(final Comparator<Person> other) { return new Comparator<Person>() { public int compare(Person o1, Person o2) { return -1 * other.compare(o1, o2); } }; } public static Comparator<Person> getComparator(final PersonComparator... multipleOptions) { return new Comparator<Person>() { public int compare(Person o1, Person o2) { for (PersonComparator option : multipleOptions) { int result = option.compare(o1, o2); if (result != 0) { return result; } } return 0; } }; } } 

使用示例(使用静态导入)。

 public static void main(String[] args) { List<Person> list = null; Collections.sort(list, decending(getComparator(NAME_SORT, ID_SORT))); } 

你可以为你想要sorting的每个属性创build比较器,然后尝试“比较器链接”:-),如下所示:

 public class ChainedComparator<T> implements Comparator<T> { private List<Comparator<T>> simpleComparators; public ChainedComparator(Comparator<T>... simpleComparators) { this.simpleComparators = Arrays.asList(simpleComparators); } public int compare(T o1, T o2) { for (Comparator<T> comparator : simpleComparators) { int result = comparator.compare(o1, o2); if (result != 0) { return result; } } return 0; } } 

一种方法是创build一个Comparator ,以参数的forms列出要sorting的属性,如本例所示。

 public class Person { private int id; private String name, address; public static Comparator<Person> getComparator(SortParameter... sortParameters) { return new PersonComparator(sortParameters); } public enum SortParameter { ID_ASCENDING, ID_DESCENDING, NAME_ASCENDING, NAME_DESCENDING, ADDRESS_ASCENDING, ADDRESS_DESCENDING } private static class PersonComparator implements Comparator<Person> { private SortParameter[] parameters; private PersonComparator(SortParameter[] parameters) { this.parameters = parameters; } public int compare(Person o1, Person o2) { int comparison; for (SortParameter parameter : parameters) { switch (parameter) { case ID_ASCENDING: comparison = o1.id - o2.id; if (comparison != 0) return comparison; break; case ID_DESCENDING: comparison = o2.id - o1.id; if (comparison != 0) return comparison; break; case NAME_ASCENDING: comparison = o1.name.compareTo(o2.name); if (comparison != 0) return comparison; break; case NAME_DESCENDING: comparison = o2.name.compareTo(o1.name); if (comparison != 0) return comparison; break; case ADDRESS_ASCENDING: comparison = o1.address.compareTo(o2.address); if (comparison != 0) return comparison; break; case ADDRESS_DESCENDING: comparison = o2.address.compareTo(o1.address); if (comparison != 0) return comparison; break; } } return 0; } } } 

然后可以在代码中使用它,例如:

 cp = Person.getComparator(Person.SortParameter.ADDRESS_ASCENDING, Person.SortParameter.NAME_DESCENDING); Collections.sort(personList, cp); 

一种方法是组成Comparator 。 这可能是一个库方法(我确定它存在的地方)。

 public static <T> Comparator<T> compose( final Comparator<? super T> primary, final Comparator<? super T> secondary ) { return new Comparator<T>() { public int compare(T a, T b) { int result = primary.compare(a, b); return result==0 ? secondary.compare(a, b) : result; } [...] }; } 

使用:

 Collections.sort(people, compose(nameComparator, addressComparator)); 

或者,请注意Collections.sort是一个稳定的sorting。 如果performance不是绝对至关重要的,那么在小学之前你就是二级学位。

 Collections.sort(people, addressComparator); Collections.sort(people, nameComparator); 

比较器可以让你轻松自然地做到这一点。 您可以创build比较器的单个实例,既可以在Person类本身中创build,也可以在与您需要关联的Service类中创build。
例子,使用匿名内部类:

  public static final Comparator<Person> NAME_ASC_ADRESS_DESC = new Comparator<Person>() { public int compare(Person p1, Person p2) { int nameOrder = p1.getName().compareTo(p2.getName); if(nameOrder != 0) { return nameOrder; } return -1 * p1.getAdress().comparedTo(p2.getAdress()); // I use explicit -1 to be clear that the order is reversed } }; public static final Comparator<Person> ID_DESC = new Comparator<Person>() { public int compare(Person p1, Person p2) { return -1 * p1.getId().comparedTo(p2.getId()); // I use explicit -1 to be clear that the order is reversed } }; // and other comparator instances as needed... 

如果你有很多,你也可以用你喜欢的方式来构build你的比较代码 。 例如,您可以:

  • 从另一个比较器inheritance,
  • 有一个CompositeComparator,它可以聚合一些现有的比较器
  • 有一个处理null情况的NullComparator,然后委托给另一个比较器
  • 等等…

我认为将分拣机与Person类结合起来,就像在你的答案中一样,不是一个好主意,因为它将比较(通常是业务驱动的)和模型对象耦合起来。 每次您想要更改/添加分拣机时,都需要触摸人员类别,这通常是您不想做的事情。

使用提供Comparator实例的服务或类似的东西,比如KLE提出的,听起来更加灵活和可扩展。

我的方法是build立在伊's的基础之上的。 主要的差距在于,没有办法先sorting一个属性,然后再sorting。 这不能用枚举来完成。 为此,我使用类。 因为SortOrder强烈依赖于我喜欢的types来实现它作为人的内部类。

具有内部类“SortOrder”的类“Person”:

 import java.util.Comparator; public class Person { private int id; private String firstName; private String secondName; public Person(int id, String firstName, String secondName) { this.id = id; this.firstName = firstName; this.secondName = secondName; } public abstract static class SortOrder implements Comparator<Person> { public static SortOrder PERSON_ID = new SortOrder() { public int compare(Person p1, Person p2) { return Integer.valueOf(p1.getId()).compareTo(p2.getId()); } }; public static SortOrder PERSON_FIRST_NAME = new SortOrder() { public int compare(Person p1, Person p2) { return p1.getFirstName().compareTo(p2.getFirstName()); } }; public static SortOrder PERSON_SECOND_NAME = new SortOrder() { public int compare(Person p1, Person p2) { return p1.getSecondName().compareTo(p2.getSecondName()); } }; public static SortOrder invertOrder(final SortOrder toInvert) { return new SortOrder() { public int compare(Person p1, Person p2) { return -1 * toInvert.compare(p1, p2); } }; } public static Comparator<Person> combineSortOrders(final SortOrder... multipleSortOrders) { return new Comparator<Person>() { public int compare(Person p1, Person p2) { for (SortOrder personComparator: multipleSortOrders) { int result = personComparator.compare(p1, p2); if (result != 0) { return result; } } return 0; } }; } } public int getId() { return id; } public String getFirstName() { return firstName; } public String getSecondName() { return secondName; } @Override public String toString() { StringBuilder result = new StringBuilder(); result.append("Person with id: "); result.append(id); result.append(" and firstName: "); result.append(firstName); result.append(" and secondName: "); result.append(secondName); result.append("."); return result.toString(); } } 

使用类Person和它的SortOrder的例子:

 import static multiplesortorder.Person.SortOrder.*; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.List; import multiplesortorder.Person; public class Application { public static void main(String[] args) { List<Person> listPersons = new ArrayList<Person>(Arrays.asList( new Person(0, "...", "..."), new Person(1, "...", "...") )); Collections.sort(listPersons, combineSortOrders(PERSON_FIRST_NAME, invertOrder(PERSON_ID))); for (Person p: listPersons) { System.out.println(p.toString()); } } } 

oRUMOo

我最近写了一个比较器来sorting分隔stringlogging中的多个字段。 它允许你定义分隔符,logging结构和sorting规则(其中一些是types特定的)。 您可以通过将人员logging转换为分隔string来使用它。

所需信息以编程方式或通过XML文件播种到比较器本身。

XML由embedded式XSD文件进行validation。 例如,下面是一个带有四个字段(其中两个可sorting)的制表符分隔的logging布局:

 <?xml version="1.0" encoding="ISO-8859-1"?> <row xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> <delimiter>&#009;</delimiter> <column xsi:type="Decimal"> <name>Column One</name> </column> <column xsi:type="Integer"> <name>Column Two</name> </column> <column xsi:type="String"> <name>Column Three</name> <sortOrder>2</sortOrder> <trim>true</trim> <caseSensitive>false</caseSensitive> <stripAccents>true</stripAccents> </column> <column xsi:type="DateTime"> <name>Column Four</name> <sortOrder>1</sortOrder> <ascending>true</ascending> <nullLowSortOrder>true</nullLowSortOrder> <trim>true</trim> <pattern>yyyy-MM-dd</pattern> </column> </row> 

然后你可以像这样在java中使用它:

 Comparator<String> comparator = new RowComparator( new XMLStructureReader(new File("layout.xml"))); 

图书馆可以在这里find:

http://sourceforge.net/projects/multicolumnrowcomparator/

假设一个类Coordinate在那里,并且需要根据X坐标和Y坐标两种方式对它进行sorting。 它需要两个不同的比较器。 下面是示例

 class Coordinate { int x,y; public Coordinate(int x, int y) { this.x = x; this.y = y; } static Comparator<Coordinate> getCoordinateXComparator() { return new Comparator<Coordinate>() { @Override public int compare(Coordinate Coordinate1, Coordinate Coordinate2) { if(Coordinate1.x < Coordinate2.x) return 1; else return 0; } // compare using Coordinate x }; } static Comparator<Coordinate> getCoordinateYComparator() { return new Comparator<Coordinate>() { @Override public int compare(Coordinate Coordinate1, Coordinate Coordinate2) { if(Coordinate1.y < Coordinate2.y) return 1; else return 0; } // compare using Coordinate y }; } }