简体   繁体   English

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

[英]How to sort elements of ArrayList in ascending order? - Java

I have created a To-Do-List program where one of the actions requires the program to list all tasks input by the user in ascending order of the date that they fall on.我创建了一个待办事项列表程序,其中一项操作要求程序按照用户输入的日期的升序列出所有任务。

Output example: Output 示例:

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 

So far, with the code that I have, the tasks that the user input all list, but they don't list in ascending order of the date of each task.到目前为止,使用我拥有的代码,用户输入的任务全部列出,但它们没有按每个任务日期的升序列出。

Here is my code so far:到目前为止,这是我的代码:

public void sortTasks() {

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

Your current approach to the problem makes it hard to achieve what you want.你目前解决问题的方法很难实现你想要的。 You have a list of Strings and want to parse some fragment of them and sort based on that.您有一个字符串列表,并且想要解析其中的一些片段并根据它进行排序。 It is possible but you can make it much simplier.这是可能的,但你可以让它变得更简单。 You already got a dedicated class to represent your Task .您已经有一个专用的 class 来代表您的Task You should keep a List of Task s then, not their String representations.那么您应该保留一个TaskList ,而不是它们的 String 表示。 When you have a List<Task> , there are couple of ways to sort it.当您有List<Task>时,有几种方法可以对其进行排序。 You can either implement Comparable in your class or use a Comparator .您可以在 class 中实现Comparable或使用Comparator You could do something like that:你可以这样做:

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

Or (depending on desired order)或(取决于所需的顺序)

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

And then you use getItem() only when you want to print the results (such method is usually called toString() ).然后只有当你想打印结果时才使用getItem() (这种方法通常称为toString() )。

First of all you need to store Task objects not String in your list.首先,您需要在列表中存储不是StringTask对象。

Usually you can pass a Comparator to Collections.sort .通常您可以将Comparator器传递给Collections.sort

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

In order for that to work properly you have to make Task an implementation of Comparable , the way you compare the fields of the object depend on your specific task, here you can provide implementation for ascending comparison, and than reverse it by reverseOrder method.为了使其正常工作,您必须使Task成为Comparable的实现,比较 object 的字段的方式取决于您的具体任务,在这里您可以提供升序比较的实现,而不是通过reverseOrder方法反转它。

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

Alternately, you can create and pass to sort a more sophisticated Comparator object, without Task being a Comparable object.或者,您可以创建并传递以sort更复杂的Comparator器 object,而不是Task是可Comparable的 object。 Note though, that this approach makes code less reusable.但请注意,这种方法使代码的可重用性降低。

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

Also consider using SortedSet or PriorityQueue instead of List for your task in order to avoid explicit sorting and reduce algorithmic complexity还可以考虑为您的任务使用SortedSetPriorityQueue而不是List ,以避免显式排序并降低算法复杂性

It would be better if you just maintain a List of Task instances and sort that List .如果您只维护一个Task实例List并对该List进行排序,那会更好。

You can use one of the following options to sort a List of Task instances:您可以使用以下选项之一对Task实例List进行排序:

  1. Implementing Comparable Interface实现可比接口
  2. Using Comparator使用比较器

Implementing Comparable Interface实现可比接口

To implement Comparable interface, you must override compareTo method in Task class.要实现Comparable接口,您必须重写Task class 中的compareTo方法。 Since you want to sort Tasks based on date instance field, you can just return the result of date comparison.由于您要根据date实例字段对任务进行排序,因此您可以只返回日期比较的结果。

Here's how you should override compareTo() method to sort Tasks in ascending order based on date instance field.以下是您应该如何覆盖compareTo()方法以根据date实例字段按升序对任务进行排序。

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

Since Date class already implements Comparable interface, you can just call compareTo method to compare two Date instances.由于Date class 已经实现了Comparable接口,你可以调用compareTo方法来比较两个Date实例。

Now to sort the list of tasks, call sort method of Collections class.现在对任务列表进行排序,调用Collections class 的sort方法。

Collections.sort(taskList);

Here's a version of your code that implements Comparable interface and sorts the tasks using date instance field这是实现Comparable接口并使用date实例字段对任务进行排序的代码版本

Using Comparator使用比较器

There are more than one ways to sort objects using a Comparator interface:使用Comparator接口对对象进行排序的方法不止一种:

  • Create a separate class that implements Comparator interface创建一个单独的实现Comparator器接口的 class
  • Use anonymous class or use lambda expression使用匿名 class 或使用 lambda 表达式
  • Use static methods of Comparator interface使用比较器接口的 static 方法

Create a separate class that implements Comparator interface创建一个单独的实现比较器接口的 class

You can create a class that implements Comparator interface and then override compare function.您可以创建一个实现Comparator器接口的 class,然后覆盖compare function。 Implementation of compare function will be same as that of compareTo function implemented above by implementing Comparable interface. compare function 的实现将与上面通过实现Comparable接口实现的compareTo function 的实现相同。

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

To sort the task list, you have two options:要对任务列表进行排序,您有两种选择:

  1. Use sort function of Collections class and pass an instacne of TaskComparator class as a second argument使用 function 的Collections class 的sort function 作为第二个参数传递TaskComparator ZA2F2ED4F8EBC2CBB4DZC21

     Collections.sort(taskList, new TaskComparator());
  2. Use sort method of List interface使用List接口的sort方法

    taskList.sort(new TaskComparator());

Here's a version of your code that creates a separate comparator class to sort the tasks using date instance field这是您的代码的一个版本,它创建了一个单独的比较器 class 以使用date实例字段对任务进行排序

Use anonymous class or use lambda expression使用匿名 class 或使用 lambda 表达式

Instead of creating a separate class to implement Comparator interface, you can use an anonymous class无需创建单独的 class 来实现Comparator接口,您可以使用匿名 class

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

or或者

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

Java 8 introduced lambda expressions, you can replace anonymous class with lambda expression to make your code concise Java 8 介绍了 lambda 表达式,您可以将匿名 class 替换为 Z945F3FC4495186846

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

or或者

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

Here's a version of your code that uses lambda expression to implement Comparator interface这是您的代码版本,它使用 lambda 表达式来实现Comparator接口

Use static methods of Comparator interface使用比较器接口的 static 方法

You can also use static method named comparing of Comparator interface.您还可以使用 static 方法名为Comparator接口的comparing It will return a comparator that will be used for sorting.它将返回一个用于排序的比较器。

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

or或者

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

Here's a version of your code that uses Comparator.comparing method to sort the tasks using date instance field这是您的代码版本,它使用Comparator.comparing方法使用date实例字段对任务进行排序

For details on how to implement Comparable or Comparator interfaces, see:有关如何实现ComparableComparator接口的详细信息,请参见:

You can sort List use sort method with custom Comparator您可以使用自定义Comparator器排序List使用sort方法

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

But I think you have to use another collection.但我认为你必须使用另一个集合。 PriorityQueue feet better than ArrayList . PriorityQueue脚优于ArrayList

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

Since creating TaskList and sorting based on dates solution is already provided by @Amongalen .由于@Amongalen已经提供了创建 TaskList 和基于日期排序的解决方案。

I will provide a different approach with better Time complexity .我将提供一种具有更好时间复杂度的不同方法。 Since Sorting a collection can be O(nlogn) .由于对集合进行排序可以是O(nlogn) It is not a good idea to sort after every time you add an element to the list.每次将元素添加到列表后进行排序并不是一个好主意。

Instead you can maintain a PriorityQueue of Task Object and compare them based on date and add Task objects to that PriorityQueue .相反,您可以维护 Task Object 的PriorityQueue并根据日期比较它们并将Task对象添加到该PriorityQueue

Now you don't need to call sort, just iterate over the queue and display the result.现在您不需要调用 sort,只需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());
}

Note: adding task object to queue is O(logn) So this will improve time of your solution注意:将任务 object 添加到队列是 O(logn) 所以这将缩短您的解决方案的时间

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM