Java 使用自定义排序顺序对对象的 ArrayList 进行排序

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1814095/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-12 22:54:11  来源:igfitidea点击:

Sorting an ArrayList of objects using a custom sorting order

javasortingcollectionsarraylist

提问by Sameera0

I am looking to implement a sort feature for my address book application.

我希望为我的地址簿应用程序实现排序功能。

I want to sort an ArrayList<Contact> contactArray. Contactis a class which contains four fields: name, home number, mobile number and address. I want to sort on name.

我想对一个ArrayList<Contact> contactArray. Contact是一个包含四个字段的类:姓名、家庭号码、手机号码和地址。我想排序name

How can I write a custom sort function to do this?

如何编写自定义排序函数来执行此操作?

采纳答案by BalusC

Here's a tutorial about ordering objects:

这是有关订购对象的教程:

Although I will give some examples, I would recommend to read it anyway.

虽然我会给出一些例子,但我还是建议阅读它。



There are various way to sort an ArrayList. If you want to define a natural(default) ordering, then you need to let Contactimplement Comparable. Assuming that you want to sort by default on name, then do (nullchecks omitted for simplicity):

有多种方法可以对ArrayList. 如果你想定义一个自然(默认)排序,那么你需要让Contactimplement Comparable。假设您想默认排序 on name,然后执行(为简单起见省略了空检查):

public class Contact implements Comparable<Contact> {

    private String name;
    private String phone;
    private Address address;

    public int compareTo(Contact other) {
        return name.compareTo(other.name);
    }

    // Add/generate getters/setters and other boilerplate.
}

so that you can just do

这样你就可以做

List<Contact> contacts = new ArrayList<Contact>();
// Fill it.

Collections.sort(contacts);


If you want to define an external controllable ordering(which overrides the natural ordering), then you need to create a Comparator:

如果要定义外部可控排序(覆盖自然排序),则需要创建一个Comparator

List<Contact> contacts = new ArrayList<Contact>();
// Fill it.

// Now sort by address instead of name (default).
Collections.sort(contacts, new Comparator<Contact>() {
    public int compare(Contact one, Contact other) {
        return one.getAddress().compareTo(other.getAddress());
    }
}); 


You can even define the Comparators in the Contactitself so that you can reuse them instead of recreating them everytime:

您甚至可以ComparatorContact自身中定义s,以便您可以重用它们而不是每次都重新创建它们:

public class Contact {

    private String name;
    private String phone;
    private Address address;

    // ...

    public static Comparator<Contact> COMPARE_BY_PHONE = new Comparator<Contact>() {
        public int compare(Contact one, Contact other) {
            return one.phone.compareTo(other.phone);
        }
    };

    public static Comparator<Contact> COMPARE_BY_ADDRESS = new Comparator<Contact>() {
        public int compare(Contact one, Contact other) {
            return one.address.compareTo(other.address);
        }
    };

}

which can be used as follows:

可以按如下方式使用:

List<Contact> contacts = new ArrayList<Contact>();
// Fill it.

// Sort by address.
Collections.sort(contacts, Contact.COMPARE_BY_ADDRESS);

// Sort later by phone.
Collections.sort(contacts, Contact.COMPARE_BY_PHONE);


And to cream the top off, you could consider to use a generic javabean comparator:

为了让顶部更上一层楼,您可以考虑使用通用的 javabean 比较器

public class BeanComparator implements Comparator<Object> {

    private String getter;

    public BeanComparator(String field) {
        this.getter = "get" + field.substring(0, 1).toUpperCase() + field.substring(1);
    }

    public int compare(Object o1, Object o2) {
        try {
            if (o1 != null && o2 != null) {
                o1 = o1.getClass().getMethod(getter, new Class[0]).invoke(o1, new Object[0]);
                o2 = o2.getClass().getMethod(getter, new Class[0]).invoke(o2, new Object[0]);
            }
        } catch (Exception e) {
            // If this exception occurs, then it is usually a fault of the developer.
            throw new RuntimeException("Cannot compare " + o1 + " with " + o2 + " on " + getter, e);
        }

        return (o1 == null) ? -1 : ((o2 == null) ? 1 : ((Comparable<Object>) o1).compareTo(o2));
    }

}

which you can use as follows:

您可以按如下方式使用:

// Sort on "phone" field of the Contact bean.
Collections.sort(contacts, new BeanComparator("phone"));

(as you see in the code, possibly null fields are already covered to avoid NPE's during sort)

(正如您在代码中看到的,可能已经覆盖了空字段以避免排序期间出现 NPE)

回答by monksy

You shoud use the Arrays.sort function. The containing classes should implement Comparable.

您应该使用 Arrays.sort 函数。包含的类应该实现 Comparable。

回答by Joshua

The Collections.sort is a good sort implementation. If you don't have The comparable implemented for Contact, you will need to pass in a Comparator implementation

Collections.sort 是一个很好的排序实现。如果您没有为 Contact 实现可比较,则需要传入一个Comparator 实现

Of note:

值得注意的是:

The sorting algorithm is a modified mergesort (in which the merge is omitted if the highest element in the low sublist is less than the lowest element in the high sublist). This algorithm offers guaranteed n log(n) performance. The specified list must be modifiable, but need not be resizable. This implementation dumps the specified list into an array, sorts the array, and iterates over the list resetting each element from the corresponding position in the array. This avoids the n2 log(n) performance that would result from attempting to sort a linked list in place.

排序算法是一种改进的归并排序(如果低子列表中的最高元素小于高子列表中的最低元素,则省略合并)。该算法提供有保证的 n log(n) 性能。指定的列表必须是可修改的,但不需要可调整大小。此实现将指定的列表转储到数组中,对数组进行排序,并遍历列表,从数组中的相应位置重置每个元素。这避免了因尝试对链接列表进行排序而导致的 n2 log(n) 性能。

The merge sort is probably better than most search algorithm you can do.

归并排序可能比你能做的大多数搜索算法都要好。

回答by Kaleb Brasee

You need make your Contact classes implement Comparable, and then implement the compareTo(Contact)method. That way, the Collections.sort will be able to sort them for you. Per the page I linked to, compareTo 'returns a negative integer, zero, or a positive integer as this object is less than, equal to, or greater than the specified object.'

您需要让您的 Contact 类实现Comparable,然后实现该compareTo(Contact)方法。这样, Collections.sort 就可以为您排序。根据我链接到的页面, compareTo '返回一个负整数、零或正整数,因为该对象小于、等于或大于指定的对象。

For example, if you wanted to sort by name (A to Z), your class would look like this:

例如,如果您想按名称(A 到 Z)排序,您的类将如下所示:

public class Contact implements Comparable<Contact> {

    private String name;

    // all the other attributes and methods

    public compareTo(Contact other) {
        return this.name.compareTo(other.name);
    }
}

回答by bguiz

This pagetells you all you need to know about sorting collections, such as ArrayList.

此页面告诉您有关排序集合(例如 ArrayList)的所有信息。

Basically you need to

基本上你需要

  • make your Contactclass implement the Comparableinterface by
    • creating a method public int compareTo(Contact anotherContact)within it.
  • Once you do this, you can just call Collections.sort(myContactList);,
    • where myContactListis ArrayList<Contact>(or any other collection of Contact).
  • 让你的Contact类实现Comparable接口
    • public int compareTo(Contact anotherContact)在其中创建一个方法。
  • 一旦你这样做,你就可以打电话Collections.sort(myContactList);
    • 其中myContactListArrayList<Contact>(或任何其他集合的Contact)。

There's another way as well, involving creating a Comparator class, and you can read about that from the linked page as well.

还有另一种方法,涉及创建一个 Comparator 类,您也可以从链接页面中阅读相关内容。

Example:

例子:

public class Contact implements Comparable<Contact> {

    ....

    //return -1 for less than, 0 for equals, and 1 for more than
    public compareTo(Contact anotherContact) {
        int result = 0;
        result = getName().compareTo(anotherContact.getName());
        if (result != 0)
        {
            return result;
        }
        result = getNunmber().compareTo(anotherContact.getNumber());
        if (result != 0)
        {
            return result;
        }
        ...
    }
}

回答by Etienne Neveu

BalusC and bguiz have already given very complete answers on how to use Java's built-in Comparators.

BalusC 和 bguiz 已经给出了非常完整的关于如何使用 Java 内置比较器的答案。

I just want to add that google-collections has an Orderingclass which is more "powerful" than the standard Comparators. It might be worth checking out. You can do cool things such as compounding Orderings, reversing them, ordering depending on a function's result for your objects...

我只想补充一点,google-collections 有一个Ordering类,它比标准的 Comparator 更“强大”。可能值得一试。你可以做一些很酷的事情,比如复合排序、反转它们、根据对象的函数结果进行排序......

Hereis a blog post that mentions some of its benefits.

是一篇博客文章,其中提到了它的一些好处。

回答by Mario Fusco

By using lambdajyou can sort a collection of your contacts (for example by their name) as it follows

通过使用lambdaj,您可以对您的联系人集合进行排序(例如按他们的姓名),如下所示

sort(contacts, on(Contact.class).getName());

or by their address:

或按他们的地址:

sort(contacts, on(Contacts.class).getAddress());

and so on. More in general, it offers a DSL to access and manipulate your collections in many ways, like filtering or grouping your contacts based on some conditions, aggregate some of their property values, etc.

等等。更一般地说,它提供了一个 DSL 来以多种方式访问​​和操作您的集合,例如根据某些条件过滤或分组您的联系人,聚合他们的某些属性值等。

回答by sarath

I did it by the following way. number and name are two arraylist. I have to sort name .If any change happen to name arralist order then the number arraylist also change its order.

我是通过以下方式做到的。number 和 name 是两个数组列表。我必须对 name 进行排序。如果 name arralist order 发生任何变化,那么 number arraylist 也会改变它的 order。

public void sortval(){

        String tempname="",tempnum="";

         if (name.size()>1) // check if the number of orders is larger than 1
            {
                for (int x=0; x<name.size(); x++) // bubble sort outer loop
                {
                    for (int i=0; i < name.size()-x-1; i++) {
                        if (name.get(i).compareTo(name.get(i+1)) > 0)
                        {

                            tempname = name.get(i);

                            tempnum=number.get(i);


                           name.set(i,name.get(i+1) );
                           name.set(i+1, tempname);

                            number.set(i,number.get(i+1) );
                            number.set(i+1, tempnum);


                        }
                    }
                }
            }



}

回答by Pshemo

In addition to what was already posted you should know that since Java 8 we can shorten our code and write it like:

除了已经发布的内容之外,您还应该知道,从 Java 8 开始,我们可以缩短代码并将其编写为:

Collection.sort(yourList, Comparator.comparing(YourClass::getFieldToSortOn));

or since List now have sortmethod

或者因为 List 现在有sort方法

yourList.sort(Comparator.comparing(YourClass::getFieldToSortOn));

Explanation:

解释:

Since Java 8, functional interfaces (interfaces with only one abstract method - they can have more default or static methods) can be easily implemented using:

从 Java 8 开始,函数式接口(只有一种抽象方法的接口 - 它们可以有更多的默认或静态方法)可以使用以下方法轻松实现:

Since Comparator<T>has only one abstract method int compare(T o1, T o2)it is functional interface.

因为Comparator<T>只有一个抽象方法,int compare(T o1, T o2)所以它是函数式接口。

So instead of (example from @BalusCanswer)

所以而不是(来自@BalusC答案的例子)

Collections.sort(contacts, new Comparator<Contact>() {
    public int compare(Contact one, Contact other) {
        return one.getAddress().compareTo(other.getAddress());
    }
}); 

we can reduce this code to:

我们可以将此代码简化为:

Collections.sort(contacts, (Contact one, Contact other) -> {
     return one.getAddress().compareTo(other.getAddress());
});

We can simplify this (or any) lambda by skipping

我们可以通过跳过来简化这个(或任何)lambda

  • argument types (Java will infer them based on method signature)
  • or {return... }
  • 参数类型(Java 将根据方法签名推断它们)
  • 或者{return……}

So instead of

所以代替

(Contact one, Contact other) -> {
     return one.getAddress().compareTo(other.getAddress();
}

we can write

我们可以写

(one, other) -> one.getAddress().compareTo(other.getAddress())

Also now Comparatorhas static methods like comparing(FunctionToComparableValue)or comparing(FunctionToValue, ValueComparator)which we could use to easily create Comparators which should compare some specific values from objects.

现在Comparator也有像comparing(FunctionToComparableValue)或 之类的静态方法comparing(FunctionToValue, ValueComparator),我们可以使用它们来轻松创建比较器,它们应该比较对象中的某些特定值。

In other words we can rewrite above code as

换句话说,我们可以将上面的代码重写为

Collections.sort(contacts, Comparator.comparing(Contact::getAddress)); 
//assuming that Address implements Comparable (provides default order).

回答by Bruno Mulas

use this method:

使用这个方法:

private ArrayList<myClass> sortList(ArrayList<myClass> list) {
    if (list != null && list.size() > 1) {
        Collections.sort(list, new Comparator<myClass>() {
            public int compare(myClass o1, myClass o2) {
                if (o1.getsortnumber() == o2.getsortnumber()) return 0;
                return o1.getsortnumber() < o2.getsortnumber() ? 1 : -1;
            }
        });
    }
    return list;
}

`

`

and use: mySortedlist = sortList(myList);No need to implement comparator in your class. If you want inverse order swap 1and -1

并使用:mySortedlist = sortList(myList);无需在您的类中实现比较器。如果你想要逆序交换1-1