无法弄清楚如何以正确的顺序打印列表

时间:2017-04-03 05:10:57

标签: java

基本上我有一个具有name和startDate的对象的arraylist,它们的初始顺序类似于:

Frank 10/20/1990

Bill 1/2/1990

Frank 2/2/1990

John 9/8/1990

Bill 4/4/1990

Frank 5/1/1990

我正在尝试按照声明的名字顺序打印它们,然后按日期打印,例如,应打印最终打印:

Frank 1/1/1990

Frank 5/1/1990

Frank 10/20/1990

Bill 1/2/1990

Bill 4/4/1990

John 9/8/1990

2 个答案:

答案 0 :(得分:1)

假设您的对象类看起来像这样:

private static class MyObject {

  private final String name;
  private final Date date;

  private MyObject(String name, Date date) {
    this.name = name;
    this.date = date;
  }

  public String getName() {
    return name;
  }

  public Date getDate() {
    return date;
  }
}

您可以使用以下方法打印对象:

@Test
public void printInOrder() {
  List<MyObject> list = new ArrayList<>(); // List containing your objects
  list.add(new MyObject("Frank", Date.from(LocalDate.of(1990, 10, 20).atStartOfDay(ZoneId.systemDefault()).toInstant())));
  list.add(new MyObject("Bill", Date.from(LocalDate.of(1990, 1, 2).atStartOfDay(ZoneId.systemDefault()).toInstant())));
  list.add(new MyObject("Frank", Date.from(LocalDate.of(1990, 2, 2).atStartOfDay(ZoneId.systemDefault()).toInstant())));
  list.add(new MyObject("John", Date.from(LocalDate.of(1990, 9, 8).atStartOfDay(ZoneId.systemDefault()).toInstant())));
  list.add(new MyObject("Bill", Date.from(LocalDate.of(1990, 4, 4).atStartOfDay(ZoneId.systemDefault()).toInstant())));
  list.add(new MyObject("Frank", Date.from(LocalDate.of(1990, 5, 1).atStartOfDay(ZoneId.systemDefault()).toInstant())));

  list.stream()
      .sorted(Comparator.comparing(MyObject::getName)
                        .thenComparing(Comparator.comparing(MyObject::getDate)))
      .map(obj -> obj.getName() + " " + obj.getDate())
      .forEach(System.out::println);
}

输出:

  

Bill Tue Jan 02 00:00:00 CET 1990年   Bill Wed Apr 04 00:00:00 CEST 1990
  Frank Fri Feb 02 00:00:00 CET 1990年   Frank Tue May 01 00:00:00 CEST 1990
  Frank Sat Oct 20 00:00:00 CET 1990年   John Sat Sep 08 00:00:00 CEST 1990

这使用Java 8流和比较器链来对对象进行排序。比较器按给定属性进行比较,thenComparing用于链接它们。

<强>更新

由于我不确定我是否可能误解了您,以下是针对以下情况的第二个版本:

您希望按名称排序,但按照名称出现在原始列表中的顺序,首先出现的名称将是第一个。

在这种情况下,您必须记住一个单独的临时列表中的名称顺序(仅包含原始顺序中的唯一名称),然后可以在比较器内部使用。

此列表是通过将原始列表转换为集合(因此仅具有唯一名称),然后将此集合转换回列表(以便能够在比较器中使用indexOf)生成的。

@Test
public void printInOrder() {
  List<MyObject> list = new ArrayList<>();
  list.add(new MyObject("Frank", Date.from(LocalDate.of(1990, 10, 20).atStartOfDay(ZoneId.systemDefault()).toInstant())));
  list.add(new MyObject("Bill", Date.from(LocalDate.of(1990, 1, 2).atStartOfDay(ZoneId.systemDefault()).toInstant())));
  list.add(new MyObject("Frank", Date.from(LocalDate.of(1990, 2, 2).atStartOfDay(ZoneId.systemDefault()).toInstant())));
  list.add(new MyObject("John", Date.from(LocalDate.of(1990, 9, 8).atStartOfDay(ZoneId.systemDefault()).toInstant())));
  list.add(new MyObject("Bill", Date.from(LocalDate.of(1990, 4, 4).atStartOfDay(ZoneId.systemDefault()).toInstant())));
  list.add(new MyObject("Frank", Date.from(LocalDate.of(1990, 5, 1).atStartOfDay(ZoneId.systemDefault()).toInstant())));

  List<String> declaredNameOrder = new ArrayList<>(list.stream()
                                      .map(MyObject::getName)
                                      .collect(Collectors.toCollection(LinkedHashSet::new)));

  list.stream()
      .sorted(Comparator.<MyObject>comparingInt(o -> declaredNameOrder.indexOf(o.getName()))
                  .thenComparing(Comparator.comparing(MyObject::getDate)))
      .map(obj -> obj.getName() + " " + obj.getDate())
      .forEach(System.out::println);
}

输出:

  

Frank Fri Feb 02 00:00:00 CET 1990年   Frank Tue May 01 00:00:00 CEST 1990
  Frank Sat Oct 20 00:00:00 CET 1990年   Bill Tue Jan 02 00:00:00 CET 1990年   Bill Wed Apr 04 00:00:00 CEST 1990
  John Sat Sep 08 00:00:00 CEST 1990

答案 1 :(得分:0)

您应该分两步完成:

首先使用自定义比较器按名称命令,如:

    Collections.sort(myList, new Comparator<MyObject>() {
       public int compare(MyObject o1, MyObject o2) {
          return o1.getName().compareTo(o2.getName());
       }
    });

并将输出存储在临时列表中

第二次使用临时列表按数据排序:

    Collections.sort(myList, new Comparator<MyObject>() {
       public int compare(MyObject o1, MyObject o2) {
           return o1.getDate().compareTo(o2.getDate());
       }
    });

然后您的列表将按您的要求排序。