如何按升序对ArrayList的元素进行排序? -Java

时间:2020-07-01 07:19:44

标签: java arraylist

我创建了一个“待办事项列表”程序,其中一项操作要求该程序按用户输入的所有任务按其出现日期的升序列出所有任务。

输出示例:

Tasks listed in ascending order (earliest first):

TaskName, 20/04/2020, time, location, duration, category 
TaskName, 18/07/2020, time, location, duration, category 
TaskName, 09/08/2020, time, location, duration, category 
TaskName, 21/12/2020, time, location, duration, category 

到目前为止,使用我拥有的代码,用户输入的所有任务都会列出,但是它们并没有按照每个任务的日期的升序列出。

到目前为止,这是我的代码:

public void sortTasks() {

    System.out.println("Sorted tasks by date (earliest first): ");
    
    Collections.sort(currentList);
    
    currentList.forEach(System.out::println);
    }
}

5 个答案:

答案 0 :(得分:5)

您当前的问题解决方法很难实现您想要的目标。您有一个字符串列表,想要解析它们的一些片段并基于此进行排序。可以,但是您可以使其更简单。您已经有一个专门的课程来代表您的Task。那么您应该保留List中的Task,而不是它们的String表示形式。 当您拥有List<Task>时,可以通过几种方法对其进行排序。您可以在课堂上实现Comparable,也可以使用Comparator。您可以这样做:

currentList.sort(Comparator.comparing(Task::getDate))

或(取决于所需的顺序)

currentList.sort(Comparator.comparing(Task::getDate).reversed())

然后仅在要打印结果时才使用getItem()(这种方法通常称为toString())。

答案 1 :(得分:1)

首先,您需要在列表中存储Task个对象,而不是String个对象。

通常,您可以将Comparator传递给Collections.sort

Collections.sort(tasks, Comparator.reverseOrder());

为了使其正常工作,您必须将Task实现为Comparable,比较对象字段的方式取决于您的特定任务,在这里您可以提供升序实现比较,然后通过reverseOrder方法将其反转。

class Task implements Comparable<Task> {
    ...
    @Override
    public int compareTo(Task task) {
        return Comparator
            .comparing(Task::getTitle)
            .thenComparing(Task::getDate)
            .compare(this, task);
    }
}

或者,您可以创建更复杂的sort对象并将其传递给Comparator,而Task不是Comparable对象。 但是请注意,这种方法使代码的可重用性降低。

Collections.sort(tasks, 
    Comparator
        .comparing(Task::getTitle)
        .thenComparing(Task::getDate)
        .reverseOrder()
);

还考虑将SortedSetPriorityQueue而不是List用于您的任务,以避免显式排序并降低算法复杂度

答案 2 :(得分:1)

最好只维护List个实例中的一个Task并对该List进行排序。

您可以使用以下选项之一对List个实例中的Task个实例进行排序:

  1. 实现可比接口
  2. 使用比较器

实现可比接口

要实现Comparable接口,必须重写compareTo类中的Task方法。由于您要根据date实例字段对任务进行排序,因此只需返回日期比较的结果即可。

这是您应重写compareTo()方法以根据date实例字段按升序对任务进行排序的方法。

@Override
public int compareTo(Task o) {
    return this.date.compareTo(o.date);
}

由于Date类已经实现了Comparable接口,因此您可以调用compareTo方法来比较两个Date实例。

现在要对任务列表进行排序,请调用sort类的Collections方法。

Collections.sort(taskList);

Here's a version of your code,它实现了Comparable界面,并使用date实例字段对任务进行了排序

使用比较器

使用Comparator界面对对象进行排序的方法有多种:

  • 创建一个实现Comparator接口的单独的类
  • 使用匿名类或lambda表达式
  • 使用比较器界面的静态方法

创建一个实现Comparator接口的单独类

您可以创建一个实现Comparator接口的类,然后重写compare函数。 compare函数的实现与上面通过实现compareTo接口实现的Comparable函数的实现相同。

class TaskComparator implements Comparator<Task> {
    @Override
    public int compare(Task o1, Task o2) {
        return o1.getDate().compareTo(o2.getDate());
    }
}

要对任务列表进行排序,您有两个选择:

  1. 使用sort类的Collections函数并传递TaskComparator类的instacne作为第二个参数

    Collections.sort(taskList, new TaskComparator());
    
  2. 使用sort界面的List方法

    taskList.sort(new TaskComparator());
    

Here's a version of your code创建一个单独的比较器类,以使用date实例字段对任务进行排序

使用匿名类或使用lambda表达式

您可以使用匿名类,而不必创建单独的类来实现Comparator接口,

Collections.sort(taskList, new Comparator<Task>() {
     @Override
     public int compare(Task t1, Task t2) {
         // code to compare Task objects
     }
});

taskList.sort(new Comparator<Task>() {
      @Override
      public int compare(Task o1, Task o2) {
          return o1.getDate().compareTo(o2.getDate());
      }
});

Java 8引入了lambda表达式,您可以将匿名类替换为lambda表达式,以使代码更简洁

Collections.sort(taskList, (o1, o2) -> o1.getDate().compareTo(o2.getDate()));

taskList.sort((o1, o2) -> o1.getDate().compareTo(o2.getDate()));

Here's a version of your code,使用lambda表达式实现Comparator接口

使用比较器界面的静态方法

您还可以使用comparing接口的名为Comparator的静态方法。它将返回一个用于排序的比较器。

Collections.sort(taskList, Comparator.comparing(Task::getDate));

taskList.sort(Comparator.comparing(Task::getDate));

Here's a version of your code,使用Comparator.comparing方法使用date实例字段对任务进行排序

有关如何实现ComparableComparator接口的详细信息,请参阅:

答案 3 :(得分:0)

您可以使用List方法和自定义sort来对Comparator进行排序

list.sort(Comparator.comparing(Task::getDate).reversed());

但是我认为您必须使用另一个集合。比PriorityQueueArrayList英尺。

Queue<Task> queue = new PriorityQueue<>(Comparator.comparing(...));

答案 4 :(得分:0)

@Amongalen 已经提供了创建TaskList和基于日期排序的解决方案。

我将提供一种时间复杂度更好的方法。由于对集合进行排序可以是 O(nlogn)。每次将元素添加到列表中后,进行排序都不是一个好主意。

相反,您可以维护PriorityQueue个Task Object并根据日期进行比较,然后将Task个对象添加到该PriorityQueue中。

现在,您无需调用排序,只需在iterate上方queue并显示结果即可。

PriorityQueue<Task> queue  = new PriorityQueue<>((o1,o2)-> o1.getDate.comapreTo(o2.getDate));

// Add task object to the queue
queue.add(myTaskObject);

//iterate and display when asked
Iterator<Task> it = queue.iterator();
while(it.hasNext()) {
   System.out.println(it.next().toString());
}

注意:将任务对象添加到队列为O(logn) 这样可以缩短解决方案的时间