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


我读过有关使用比较器排序ArrayLists但在人们使用的所有示例中 compareTo 根据一些研究,这是一个字符串的方法。

我想通过它们的一个属性对自定义对象的ArrayList进行排序:Date对象 (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);
    ...
}

955
2018-05-06 21:09


起源


有关: stackoverflow.com/questions/1814095/... - BalusC
在这篇文章中回答@Yishai 演示了使用比较器链进行自定义排序和分组排序(多个参数)的枚举的优雅用法。 - gunalmel


答案:


以来 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());
    }
});

以来

您现在可以使用a以较短的形式编写最后一个示例 lambda表达式 为了 Comparator

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

List 有一个 sort(Comparator) 方法,所以你可以进一步缩短它:

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

这是一种常见的习语 内置方法 生成一个 Comparator 对于一个有 Comparable 键:

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

所有这些都是等效的形式。


1310
2018-05-06 21:18



+1提及它应该返回 int 并且你最好使用 Date#compareTo() 为了这。为什么这个没有在另一个答案之上被投票超出我的范围。此链接也可能有用: Sun.com上的对象排序教程。 - BalusC
我认为最好的答案还应该包括在Java 8中实现它的正确方法.Collections.sort(list,Comparator.comparing(MyObject :: getStartDate));哪个读取更好,更不容易出错。写返回o1.getStartDate()。compareTo(o1.getStartDate()); - Kuba
比较类应该是静态的:) - Jarmez De La Rocha
@JarmezDeLaRocha:我没有说明比较器是否在另一个类中声明;如果是,那么是的,你会想让它静止。 - Michael Myers♦
@Kuba更好,使用 List.sort()。 - shmosel


具有自然排序顺序的类(作为示例的类Number)应该实现Comparable接口,而没有自然排序顺序的类(作为示例的类)应该与比较器(或匿名比较器)一起提供类)。

两个例子:

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) {
        ...
    }
});

181
2018-05-06 21:45



我尝试过 - 但是当我想在任何其他类中访问比较器类ChairWeightComparator时,我无法访问此类(当然不是因为它不公开)。我是否需要在单独的文件中创建新的公共ChairWeightComparator类? - 我真的是第一个在3年后尝试这个或者我想念的人吗? - user387184
@ user387184 - 只需将其公开,并将其放入自己的文件中(最好也是自己的包),您就可以在项目的任何地方使用它。无需创建额外的课程! - Björn
你的意思是创建一个新文件 - 而不是一个类并放入代码:“class ChairWeightComparator实现Comparator <Chair> {....”? - user387184
@ user387184,确切 - 但关键字 public 在前面 class。 - Björn


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

Collections.sort(studList, new Comparator<Student>(){
    public int compare(Student s1, Student s2) {
        return s1.getFirstName().compareToIgnoreCase(s2.getFirstName());
    }
});

150
2018-05-06 13:50



任何人使用lambda stackoverflow.com/questions/2784514/... - Sorter
对此排序,但为每个元素提供双重值 - Sam


是的你可以。比较项目有两种选择 可比 界面,和 比较 接口。

这两种接口都允许不同的行为。 Comparable允许您使对象的行为与刚才描述的字符串一样(实际上,String实现了Comparable)。第二个,比较器,允许你做你要做的事情。你会这样做:

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

这将导致Collections.sort方法将比较器用于它的排序机制。如果ArrayList中的对象具有可比性,则可以执行以下操作:

Collections.sort(myArrayList);

集合 class包含许多这些有用的常用工具。


40
2018-05-06 21:17





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)

31
2017-09-05 13:10



要么 Collections.sort(studList, Comparator.comparing(Student::getFirstName)); - Holger
.. 要么 studList.sort(Comparator.comparing(Student::getFirstName)); - Alexis C.
在您的情况下,排序顺序将始终是升序。在我的例子中,我也关注排序顺序。谢谢先生们。 - Sorter


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

import static java.util.Comparator.comparing;

Collections.sort(list, comparing(MyObject::getStartDate));

26
2018-03-13 15:19



会很棒,但Android的最新Eclipse似乎没有:-( - user387184
@ user387184遗憾的是android不支持Java 8,虽然可能有一个 解决方法 (我没有测试过)。 - assylias
这应该是正确答案。真的很酷,java终于让你有点按属性排序而不是用比较器排序。然而,它仍然评估MyObject :: getStartDate nlogn次而不是n,如python或C#sort_by方法。 - Kuba


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());
    }

}

}

13
2018-04-03 15:32



欢迎来到stackoverflow。这个问题不久前得到了回答。在恢复旧线程之前,请确保您的响应为线程添加了一些重要内容。 - Leigh
请在答案中添加说明。 - Arashsoft
只需编译并运行。代码是评论和解释。 - CharlesW


由于技术每天都会出现,答案会随着时间的推移而改变。我看了看LambdaJ,看起来非常有趣。

你可以试着解决这些任务 LambdaJ。你可以在这里找到它: 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次),但是你能找到更易读的代码吗?


13
2018-03-12 17:49



那个排序,但为每个元素提供双重值如何避免它 - Sam
@Sam,它不应该...它按预期工作。除非您使用带有错误的新版本,我建议您将其发布到论坛中。无论如何,这个答案是在java 8之前发布的,如果你使用它,那么它将比使用lambdaj好多了 - Federico Piazza
我不得不删除foreach循环中的项目,否则它会给我每个内容的两倍。 - Sam


使用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);

如果要对包含非英文字符的字母进行排序,可以使用Locale ...下面的代码使用土耳其字符排序...

课程实施

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());

7
2018-05-28 12:11





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


5
2018-05-06 21:29