代码之家  ›  专栏  ›  技术社区  ›  Samuel

按属性对自定义对象的ArrayList排序

  •  1030
  • Samuel  · 技术社区  · 16 年前

    我读过关于使用比较器对数组列表进行排序的文章,但在人们使用的所有示例中 compareTo 根据一些研究,这是一种处理字符串的方法。

    我想按自定义对象的属性之一对其数组列表进行排序:日期对象 ( getStartDay() )通常我比较它们 item1.getStartDate().before(item2.getStartDate()) 所以我想知道我是否可以写一些像:

    public class CustomComparator {
        public boolean compare(Object object1, Object object2) {
            return object1.getStartDate().before(object2.getStartDate());
        }
    }
    
    public class RandomName {
        ...
        Collections.sort(Database.arrayList, new CustomComparator);
        ...
    }
    
    25 回复  |  直到 7 年前
        1
  •  1401
  •   Michael Myers KitsuneYMG    10 年前

    自从 Date 器具 Comparable 它有一个 compareTo 方法就像 String 做。

    所以你的习惯 Comparator 可能如下所示:

    public class CustomComparator implements Comparator<MyObject> {
        @Override
        public int compare(MyObject o1, MyObject o2) {
            return o1.getStartDate().compareTo(o2.getStartDate());
        }
    }
    

    这个 compare() 方法必须返回 int ,因此您不能直接返回 boolean 就像你计划的那样。

    你的排序代码应该和你写的差不多:

    Collections.sort(Database.arrayList, new CustomComparator());
    

    如果不需要重用比较器,那么编写所有这些内容的一个稍短的方法是将其编写为一个内联匿名类:

    Collections.sort(Database.arrayList, new Comparator<MyObject>() {
        @Override
        public int compare(MyObject o1, MyObject o2) {
            return o1.getStartDate().compareTo(o2.getStartDate());
        }
    });
    

    自从

    现在可以使用 lambda expression 对于 比较器 :

    Collections.sort(Database.arrayList, 
                            (o1, o2) -> o1.getStartDate().compareTo(o2.getStartDate()));
    

    List 有一个 sort(Comparator) 方法,因此可以进一步缩短:

    Database.arrayList.sort((o1, o2) -> o1.getStartDate().compareTo(o2.getStartDate()));
    

    这是一个很常见的成语, a built-in method 生成一个 比较器 对于一个有 可比的 关键:

    Database.arrayList.sort(Comparator.comparing(MyObject::getStartDate));
    

    所有这些都是等价形式。

        2
  •  189
  •   Björn    16 年前

    具有自然排序顺序的类(例如,类号)应实现可比较的接口,而没有自然排序顺序的类(例如,类椅子)应提供比较器(或匿名比较器类)。

    两个例子:

    public class Number implements Comparable<Number> {
        private int value;
    
        public Number(int value) { this.value = value; }
        public int compareTo(Number anotherInstance) {
            return this.value - anotherInstance.value;
        }
    }
    
    public class Chair {
        private int weight;
        private int height;
    
        public Chair(int weight, int height) {
            this.weight = weight;
            this.height = height;
        }
        /* Omitting getters and setters */
    }
    class ChairWeightComparator implements Comparator<Chair> {
        public int compare(Chair chair1, Chair chair2) {
            return chair1.getWeight() - chair2.getWeight();
        }
    }
    class ChairHeightComparator implements Comparator<Chair> {
        public int compare(Chair chair1, Chair chair2) {
            return chair1.getHeight() - chair2.getHeight();
        }
    }
    

    用途:

    List<Number> numbers = new ArrayList<Number>();
    ...
    Collections.sort(numbers);
    
    List<Chair> chairs = new ArrayList<Chair>();
    // Sort by weight:
    Collections.sort(chairs, new ChairWeightComparator());
    // Sort by height:
    Collections.sort(chairs, new ChairHeightComparator());
    
    // You can also create anonymous comparators;
    // Sort by color:
    Collections.sort(chairs, new Comparator<Chair>() {
        public int compare(Chair chair1, Chair chair2) {
            ...
        }
    });
    
        3
  •  153
  •   blackpanther    12 年前

    用于排序 ArrayList 您可以使用以下代码段:

    Collections.sort(studList, new Comparator<Student>(){
        public int compare(Student s1, Student s2) {
            return s1.getFirstName().compareToIgnoreCase(s2.getFirstName());
        }
    });
    
        4
  •  41
  •   aperkins    16 年前

    是的,你可以。比较项目有两个选项,即 Comparable 接口,以及 Comparator 接口。

    这两个接口都允许不同的行为。Comparable允许您使对象的行为类似于刚刚描述的字符串(实际上,字符串实现是可比较的)。第二个,比较器,允许你做你要求做的事情。您可以这样做:

    Collections.sort(myArrayList, new MyComparator());
    

    这将导致collections.sort方法为其排序机制使用comparator。如果arraylist中的对象实现可比性,则可以这样做:

    Collections.sort(myArrayList);
    

    这个 Collections 类包含许多有用的、通用的工具。

        5
  •  36
  •   Sorter    10 年前

    Java 8 lambda表达式

    Collections.sort(studList, (Student s1, Student s2) ->{
            return s1.getFirstName().compareToIgnoreCase(s2.getFirstName());
    });
    

    Comparator<Student> c = (s1, s2) -> s1.firstName.compareTo(s2.firstName);
    studList.sort(c)
    
        6
  •  29
  •   assylias    12 年前

    使用Java 8,可以使用比较器的方法引用:

    import static java.util.Comparator.comparing;
    
    Collections.sort(list, comparing(MyObject::getStartDate));
    
        7
  •  13
  •   CharlesW    14 年前
    import java.text.ParseException;
    import java.text.SimpleDateFormat;
    import java.util.ArrayList;
    import java.util.Collections;
    import java.util.Comparator;
    import java.util.Date;
    
    public class test {
    
    public static class Person {
        public String name;
        public int id;
        public Date hireDate;
    
        public Person(String iname, int iid, Date ihireDate) {
            name = iname;
            id = iid;
            hireDate = ihireDate;
        }
    
        public String toString() {
            return name + " " + id + " " + hireDate.toString();
        }
    
        // Comparator
        public static class CompId implements Comparator<Person> {
            @Override
            public int compare(Person arg0, Person arg1) {
                return arg0.id - arg1.id;
            }
        }
    
        public static class CompDate implements Comparator<Person> {
            private int mod = 1;
            public CompDate(boolean desc) {
                if (desc) mod =-1;
            }
            @Override
            public int compare(Person arg0, Person arg1) {
                return mod*arg0.hireDate.compareTo(arg1.hireDate);
            }
        }
    }
    
    public static void main(String[] args) {
        // TODO Auto-generated method stub
        SimpleDateFormat df = new SimpleDateFormat("mm-dd-yyyy");
        ArrayList<Person> people;
        people = new ArrayList<Person>();
        try {
            people.add(new Person("Joe", 92422, df.parse("12-12-2010")));
            people.add(new Person("Joef", 24122, df.parse("1-12-2010")));
            people.add(new Person("Joee", 24922, df.parse("12-2-2010")));
        } catch (ParseException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    
        Collections.sort(people, new Person.CompId());
        System.out.println("BY ID");
        for (Person p : people) {
            System.out.println(p.toString());
        }
    
        Collections.sort(people, new Person.CompDate(false));
        System.out.println("BY Date asc");
        for (Person p : people) {
            System.out.println(p.toString());
        }
        Collections.sort(people, new Person.CompDate(true));
        System.out.println("BY Date desc");
        for (Person p : people) {
            System.out.println(p.toString());
        }
    
    }
    
    }
    
        8
  •  13
  •   Federico Piazza    12 年前

    因为技术每天都会出现,答案会随着时间的推移而改变。我看了一眼兰姆达吉,看起来很有趣。

    你可以试着用 兰布达 . 你可以在这里找到它: http://code.google.com/p/lambdaj/

    这里有一个例子:

    排序迭代

    List<Person> sortedByAgePersons = new ArrayList<Person>(persons);
    Collections.sort(sortedByAgePersons, new Comparator<Person>() {
            public int compare(Person p1, Person p2) {
               return Integer.valueOf(p1.getAge()).compareTo(p2.getAge());
            }
    });
    

    用lambda排序

    List<Person> sortedByAgePersons = sort(persons, on(Person.class).getAge()); 
    

    当然,在性能上有这种美的影响(平均是2倍),但是你能找到一个更可读的代码吗?

        9
  •  9
  •   Ucdemir    10 年前

    Java 8的最简单的方法是英语字母排序。

    类实现

    public class NewspaperClass implements Comparable<NewspaperClass>{
       public String name;
    
       @Override
       public int compareTo(NewspaperClass another) {
          return name.compareTo(another.name);
       }
    }
    

    排序

      Collections.sort(Your List);
    

    如果要对包含非英语字符的字母表进行排序,可以使用区域设置…下面的代码使用土耳其字符排序…

    类实现

    public class NewspaperClass implements Comparator<NewspaperClass> {
       public String name;
       public Boolean isUserNewspaper=false;
       private Collator trCollator = Collator.getInstance(new Locale("tr_TR"));
    
    
    
       @Override
       public int compare(NewspaperClass lhs, NewspaperClass rhs) {
          trCollator.setStrength(Collator.PRIMARY);
          return trCollator.compare(lhs.name,rhs.name);
       }
    }
    

    排序

    Collections.sort(your array list,new NewspaperClass());
    
        10
  •  6
  •   Neil Masson    10 年前

    Java 8 然后我们就不用再使用了 Collections.sort() 直接。 List 接口具有默认值 sort() 方法:

    List<User> users = Arrays.asList(user1,user2,user3);
    users.sort( (u1, u2) -> { 
    return u1.getFirstName.compareTo(u2.getFirstName());}); 
    

    http://visvv.blogspot.in/2016/01/sorting-objects-in-java-8.html .

        11
  •  6
  •   Basil Bourque    7 年前

    函数和方法引用

    这个 Collections.sort 方法可以对 List 使用A Comparator 你通过。那 比较器 可以使用 Comparator.comparing 方法,您可以通过 method reference 必要时 Function . 幸运的是,实际的代码比这个描述简单得多,而且短得多。

    对于Java 8:

    Collections.sort(list, comparing(ClassName::getName));
    

    Collections.sort(list, comparing(ClassName::getName).reversed());
    

    另一种方式是

    Collections.sort(list, comparing(ClassName::getName, Comparator.nullsLast(Comparator.naturalOrder())));
    
        12
  •  5
  •   camickr    16 年前

    你可以使用 Bean Comparator 对自定义类中的任何属性进行排序。

        13
  •  5
  •   Community Mohan Dere    9 年前

    是的,例如在 this answer 我按财产分类 v 班里的 IndexValue

        // Sorting by property v using a custom comparator.
        Arrays.sort( array, new Comparator<IndexValue>(){
            public int compare( IndexValue a, IndexValue b ){
                return a.v - b.v;
            }
        });
    

    如果你注意到这里,我正在创建一个 匿名内部类 (它是关闭的Java)并直接传递给 sort 类的方法 Arrays

    您的对象也可以实现 Comparable (这就是Java中的字符串和大多数核心库所做的),但是它将定义它自己类的“自然排序”,并且不允许插入新的排序顺序。

        14
  •  5
  •   Vitalii Fedorenko    13 年前

    你可以尝尝番石榴 Ordering :

    Function<Item, Date> getStartDate = new Function<Item, Date>() {
        public Date apply(Item item) {
            return item.getStartDate();
        }
    };
    
    List<Item> orderedItems = Ordering.natural().onResultOf(getStartDate).
                              sortedCopy(items);
    
        15
  •  5
  •   Pshemo    10 年前

    Java 8 lambda缩短了排序。

    Collections.sort(stdList, (o1, o2) -> o1.getName().compareTo(o2.getName()));
    
        16
  •  5
  •   Seeker    9 年前

    可以使用Java 8进行排序。

    yourList.sort(Comparator.comparing(Classname::getName));
    
    or
    
    yourList.stream().forEach(a -> a.getBObjects().sort(Comparator.comparing(Classname::getValue)));
    
        17
  •  4
  •   Kevin Parker    14 年前

    我发现,如果不是所有的答案都依赖于底层类(对象)来实现Comparable,或者拥有一个与助手类似的接口。

    不是我的解决方案!下面的代码允许您通过知道对象的字符串名称来比较对象的字段。您可以很容易地修改它,不使用这个名称,但是您需要公开它或构造一个要与之比较的对象。

    Collections.sort(anArrayListOfSomeObjectPerhapsUsersOrSomething, new ReflectiveComparator(). new ListComparator("name"));
    
    public class ReflectiveComparator {
        public class FieldComparator implements Comparator<Object> {
            private String fieldName;
    
            public FieldComparator(String fieldName){
                this.fieldName = fieldName;
            }
    
            @SuppressWarnings({ "unchecked", "rawtypes" })
            @Override
            public int compare(Object object1, Object object2) {
                try {
                    Field field = object1.getClass().getDeclaredField(fieldName);
                    field.setAccessible(true);
    
                    Comparable object1FieldValue = (Comparable) field.get(object1);
                    Comparable object2FieldValue = (Comparable) field.get(object2);
    
                    return object1FieldValue.compareTo(object2FieldValue);
                }catch (Exception e){}
    
                return 0;
            }
        }
    
        public class ListComparator implements Comparator<Object> {
            private String fieldName;
    
            public ListComparator(String fieldName) {
                this.fieldName = fieldName;
            }
    
            @SuppressWarnings({ "unchecked", "rawtypes" })
            @Override
            public int compare(Object object1, Object object2) {
                try {
                    Field field = object1.getClass().getDeclaredField(fieldName);
                    field.setAccessible(true);
                    Comparable o1FieldValue = (Comparable) field.get(object1);
                    Comparable o2FieldValue = (Comparable) field.get(object2);
    
                    if (o1FieldValue == null){ return -1;}
                    if (o2FieldValue == null){ return 1;}
                    return o1FieldValue.compareTo(o2FieldValue);
                } catch (NoSuchFieldException e) {
                    throw new IllegalStateException("Field doesn't exist", e);
                } catch (IllegalAccessException e) {
                    throw new IllegalStateException("Field inaccessible", e);
                }
            }
        }
    }
    
        18
  •  3
  •   Laura Liparulo    13 年前

    此代码段可能很有用。如果要对对象排序 在我的示例中,我希望按卷名排序:

    public List<Volume> getSortedVolumes() throws SystemException {
        List<Volume> volumes = VolumeLocalServiceUtil.getAllVolumes();
        Collections.sort(volumes, new Comparator<Volume>() {
            public int compare(Volume o1, Volume o2) {
                Volume p1 = (Volume) o1;
                Volume p2 = (Volume) o2;
                return p1.getVolumeName().compareToIgnoreCase(
                        p2.getVolumeName());
            }
        });
        return volumes;
    }
    

    这是可行的。我在JSP中使用它。

        19
  •  3
  •   GhostCat    9 年前

    你可以看看这个 presentation 2016在斯图加特德国举行JAVA论坛。

    只有少数幻灯片使用德语,99%的内容是“基于英语”的Java源代码;

    someCollection.sort(
      OurCustomComparator
        .comparing(Person::getName)
        .thenComparing(Person::getId)
    );
    

    哪里 OurCustomComparator 使用默认方法(和其他有趣的想法)。如图所示,导致非常简洁的代码选择一些getter方法进行排序;以及排序条件的超简单链接(或反转)。

    如果你对Java8感兴趣,你会在那里找到很多材料让你开始学习。

        20
  •  2
  •   Vinny    16 年前

    CustomComparator类必须实现java.util.Comparator才能使用。 它还必须覆盖compare()和equals()。

    compare()必须回答以下问题:对象1是小于、等于还是大于对象2?

    完整文档: http://java.sun.com/j2se/1.5.0/docs/api/java/util/Comparator.html

        21
  •  2
  •   Shriram M.    10 年前

    有了这个图书馆 here 可以对多列上的自定义对象列表进行排序。该库使用8.0版功能。那里也有样品。这是一个样品

    SortKeys sortKeys = new SortKeys();
    sortKeys.addField("firstName")
                .addField("age", true); // This (true) will sort the age descending
    
    // Other ways to specify a property to the sorter are
    //      .addField("lastName", String.class);
    //      .addField("dob", Date.class, true);
    
    // Instantiate a ListSorter
    ListSorter listSorter = new ListSorter();
    
    // Pass the data to sort (listToSort) and the "by keys" to sort (sortKeys)
    List sortedList = (List<Person>) listSorter.sortList(listToSort, sortKeys);
    
        22
  •  2
  •   TylerH Ash Burlaczenko    7 年前

    自1.8以来新增的是list.sort()方法,而不是使用collection.sort()。 所以直接调用myListContainer.sort()。

    下面是演示list.sort()功能的代码段:

    List<Fruit> fruits = new ArrayList<Fruit>();
    fruits.add(new Fruit("Kiwi","green",40));
    fruits.add(new Fruit("Banana","yellow",100));
    fruits.add(new Fruit("Apple","mixed green,red",120));
    fruits.add(new Fruit("Cherry","red",10));
    
    // a) using an existing compareto() method
    fruits.sort((Fruit f1,Fruit f2) -> f1.getFruitName().compareTo(f2.getFruitName()));
    System.out.println("Using String.compareTo(): " + fruits);
    //Using String.compareTo(): [Apple is: mixed green,red, Banana is: yellow, Cherry is: red, Kiwi is: green]
    
    // b) Using a comparable class
    fruits.sort((Fruit f1,Fruit f2) -> f1.compareTo(f2));  
    System.out.println("Using a Comparable Fruit class (sort by color): " + fruits);
    // Using a Comparable Fruit class (sort by color): [Kiwi is green, Apple is: mixed green,red, Cherry is: red, Banana is: yellow]
    

    水果类为:

    public class Fruit implements Comparable<Fruit>
    {
        private String name;
        private String color;
        private int quantity;
    
        public Fruit(String name,String color,int quantity)
        { this.name = name; this.color = color; this.quantity = quantity; }
    
        public String getFruitName() { return name; }        
        public String getColor() { return color; }  
        public int getQuantity() { return quantity; }
    
        @Override public final int compareTo(Fruit f) // sorting the color
        {
            return this.color.compareTo(f.color);
        }     
        @Override public String toString()
        {   
            return (name + " is: " + color);
        }
    } // end of Fruit class   
    
        23
  •  1
  •   DDus    16 年前

    我更喜欢这个过程:

    public class SortUtil
    {    
        public static <T> List<T> sort(List<T> list, String sortByProperty)
        {
                Collections.sort(list, new BeanComparator(sortByProperty));
                return list;
        }
    }
    
    List<T> sortedList = SortUtil<T>.sort(unsortedList, "startDate");
    

    如果对象列表中有一个名为 startDate ,你一次又一次的使用这个。你甚至可以把它们拴起来 startDate.time .

    这要求您的对象是 Comparable 这意味着你需要一个 compareTo , equals hashCode 实施。

    是的,可能会更快…但是现在您不必为每种类型制作一个新的比较器。如果您可以节省开发时间并放弃运行时,那么您可以使用这个方法。

        24
  •  0
  •   Sahil Chhabra    8 年前

    使用Java 8可以定义 Comparator 在一行中使用 Comparator.comparing()

    使用以下任何一种方法:

    选项1:

    listToBeSorted.sort(Comparator.comparing(CustomObject::getStartDate));
    

    选项2:

    Collections.sort(listToBeSorted, Comparator.comparing(CustomObject::getStartDate));
    
        25
  •  0
  •   Nullbeans    7 年前

    自定义类可以实现“Comparable”接口,这需要实现CompareTo方法。在CompareTo方法中,然后可以定义对象的含义 小于或大于 另一个对象。所以在您的示例中,它可以看起来像这样:

    public class MyCustomClass implements Comparable<MyCustomClass>{
    

    ……

     @Override
    public int compareTo(MyCustomClass a) {
        if(this.getStartDate().before(a.getStartDate())){
            return -1;
        }else if(a.getStartDate().before(this.getStartDate())){
            return 1;
        }else {
            return 0;
        }
    }
    

    负数表示 小于要比较的对象。正数表示 大于“比较对象”,零表示对象相等。

    然后,您可以使用collections.sort(mylist)对列表进行排序,而无需输入比较器。如果使用像treeset或treemap这样的已排序收集数据结构,此方法还具有自动排序的优点。

    如果您想了解更多关于可比较接口的信息(公开:我是作者;)可以查看本文。 https://nullbeans.com/the-java-comparable-interface-automatic-sort-of-collections/