我有对象数组person (int age; String name;)

如何按名称和年龄先后按字母顺序对数组进行排序?

您将使用哪种算法?

#1 楼

您可以按以下方式使用Collections.sort

private static void order(List<Person> persons) {

    Collections.sort(persons, new Comparator() {

        public int compare(Object o1, Object o2) {

            String x1 = ((Person) o1).getName();
            String x2 = ((Person) o2).getName();
            int sComp = x1.compareTo(x2);

            if (sComp != 0) {
               return sComp;
            } 

            Integer x1 = ((Person) o1).getAge();
            Integer x2 = ((Person) o2).getAge();
            return x1.compareTo(x2);
    }});
}


现在按名称,然后按年龄对List<Persons>进行排序。

String.compareTo“按字典顺序比较两个字符串” -来自文档。

Collections.sort是本机Collections库中的静态方法。它会进行实际的排序,您只需要提供一个Comparator即可定义应该如何比较列表中的两个元素:这是通过提供您自己的compare方法的实现来实现的。

评论


您还可以将类型参数添加到Comparator以避免强制转换输入。

–biziclop
2011年1月26日下午14:36

@Ralph:我已经修改了答案,并添加了简短说明。

–Richard H
2011-1-26 14:53

由于OP已经具有自己的对象类,因此实现Comparable更为有意义。查看@ berry120的答案

–祖拉夏
2012年3月31日上午8:56

小型代码审查:else子句是多余的,因为第一个返回充当保护子句。很好的答案,但是为我工作了。

–汤姆·萨利巴(Tom Saleeba)
2014年9月17日下午6:19

由于此问题/答案仍然联系在一起,请注意,使用Java SE 8变得更加简单。如果有吸气剂,则可以编写Comparator 比较器= Comparator.comparing(Person :: getName).thenComparingInt(Person :: getAge);

– Puce
16年1月22日在16:33



#2 楼

对于那些能够使用Java 8流API的人来说,这里有一种更整洁的方法,在这里有详细记录:
Lambda和排序

我一直在寻找与C#LINQ等效的方法:

.ThenBy(...)


我在比较器上的Java 8中找到了该机制:

.thenComparing(...)


所以这是演示的代码段

    Comparator<Person> comparator = Comparator.comparing(person -> person.name);
    comparator = comparator.thenComparing(Comparator.comparing(person -> person.age));


查阅上面的链接,获得更整洁的方法,并说明Java的类型推断与LINQ相比如何使它的定义更加笨拙。

这是完整的单元测试,供参考:

@Test
public void testChainedSorting()
{
    // Create the collection of people:
    ArrayList<Person> people = new ArrayList<>();
    people.add(new Person("Dan", 4));
    people.add(new Person("Andi", 2));
    people.add(new Person("Bob", 42));
    people.add(new Person("Debby", 3));
    people.add(new Person("Bob", 72));
    people.add(new Person("Barry", 20));
    people.add(new Person("Cathy", 40));
    people.add(new Person("Bob", 40));
    people.add(new Person("Barry", 50));

    // Define chained comparators:
    // Great article explaining this and how to make it even neater:
    // http://blog.jooq.org/2014/01/31/java-8-friday-goodies-lambdas-and-sorting/
    Comparator<Person> comparator = Comparator.comparing(person -> person.name);
    comparator = comparator.thenComparing(Comparator.comparing(person -> person.age));

    // Sort the stream:
    Stream<Person> personStream = people.stream().sorted(comparator);

    // Make sure that the output is as expected:
    List<Person> sortedPeople = personStream.collect(Collectors.toList());
    Assert.assertEquals("Andi",  sortedPeople.get(0).name); Assert.assertEquals(2,  sortedPeople.get(0).age);
    Assert.assertEquals("Barry", sortedPeople.get(1).name); Assert.assertEquals(20, sortedPeople.get(1).age);
    Assert.assertEquals("Barry", sortedPeople.get(2).name); Assert.assertEquals(50, sortedPeople.get(2).age);
    Assert.assertEquals("Bob",   sortedPeople.get(3).name); Assert.assertEquals(40, sortedPeople.get(3).age);
    Assert.assertEquals("Bob",   sortedPeople.get(4).name); Assert.assertEquals(42, sortedPeople.get(4).age);
    Assert.assertEquals("Bob",   sortedPeople.get(5).name); Assert.assertEquals(72, sortedPeople.get(5).age);
    Assert.assertEquals("Cathy", sortedPeople.get(6).name); Assert.assertEquals(40, sortedPeople.get(6).age);
    Assert.assertEquals("Dan",   sortedPeople.get(7).name); Assert.assertEquals(4,  sortedPeople.get(7).age);
    Assert.assertEquals("Debby", sortedPeople.get(8).name); Assert.assertEquals(3,  sortedPeople.get(8).age);
    // Andi     : 2
    // Barry    : 20
    // Barry    : 50
    // Bob      : 40
    // Bob      : 42
    // Bob      : 72
    // Cathy    : 40
    // Dan      : 4
    // Debby    : 3
}

/**
 * A person in our system.
 */
public static class Person
{
    /**
     * Creates a new person.
     * @param name The name of the person.
     * @param age The age of the person.
     */
    public Person(String name, int age)
    {
        this.age = age;
        this.name = name;
    }

    /**
     * The name of the person.
     */
    public String name;

    /**
     * The age of the person.
     */
    public int age;

    @Override
    public String toString()
    {
        if (name == null) return super.toString();
        else return String.format("%s : %d", this.name, this.age);
    }
}


评论


这种比较器链接的复杂性是什么?每次链接比较器时,我们是否都在进行排序?那么我们为每个比较器执行NlogN操作吗?

–约翰·鲍姆(John Baum)
2015年11月10日在16:49

如果有吸气剂,则可以编写Comparator 比较器= Comparator.comparing(Person :: getName).thenComparing(Person :: getAge);

– Puce
16年1月22日在16:27



使用thenComparingInt作为年龄(int)

– Puce
16年1月22日在16:36



拉达文字'->'的语法对我不起作用。 Person :: getLastName可以。

–诺迪
16-3-30在7:21



创建比较器之后,需要创建一个流,用比较器对其进行排序,然后收集它吗?您可以使用Collections.sort(people,比较器);代替?

– Anish Sana
18/09/11在21:24

#3 楼

使用Java 8 Streams方法...

//Creates and sorts a stream (does not sort the original list)       
persons.stream().sorted(Comparator.comparing(Person::getName).thenComparing(Person::getAge));


和Java 8 Lambda方法...

//Sorts the original list Lambda style
persons.sort((p1, p2) -> {
        if (p1.getName().compareTo(p2.getName()) == 0) {
            return p1.getAge().compareTo(p2.getAge());
        } else {
            return p1.getName().compareTo(p2.getName());
        } 
    });


最后...

//This is similar SYNTAX to the Streams above, but it sorts the original list!!
persons.sort(Comparator.comparing(Person::getName).thenComparing(Person::getAge));


#4 楼

您可以使用Java 8 Lambda方法来实现。
喜欢:

persons.sort(Comparator.comparing(Person::getName).thenComparing(Person::getAge));


评论


这对我来说非常有效,我认为这是最干净的解决方案!

– AleksandarT
12月12日9:56

指向重点。谢谢@mustafa

–Georgios Stathis
7小时前



#5 楼

您需要实现自己的Comparator,然后使用它:例如,

Arrays.sort(persons, new PersonComparator());


您的比较器可能看起来像这样:

public class PersonComparator implements Comparator<? extends Person> {

  public int compare(Person p1, Person p2) {
     int nameCompare = p1.name.compareToIgnoreCase(p2.name);
     if (nameCompare != 0) {
        return nameCompare;
     } else {
       return Integer.valueOf(p1.age).compareTo(Integer.valueOf(p2.age));
     }
  }
}


比较器首先比较名称,如果名称不相等则返回比较结果,否则比较两个人的年龄时返回比较结果。

这段代码只是草稿:因为该类是不可变的,所以您可以考虑建立一个单例,而不是为每次排序创建一个新实例。

#6 楼

让您的人员类实现Comparable<Person>,然后实现compareTo方法,例如:

public int compareTo(Person o) {
    int result = name.compareToIgnoreCase(o.name);
    if(result==0) {
        return Integer.valueOf(age).compareTo(o.age);
    }
    else {
        return result;
    }
}


这将首先按名称(不区分大小写)排序,然后按年龄排序。然后,可以在Person对象的集合或数组上运行Arrays.sort()Collections.sort()

评论


我通常更喜欢使用Comparator,因为正如berry120所说,您可以使用内置方法进行排序,而不需要始终使用自定义Comparator。

–祖拉夏
2012年3月31日上午8:51

#7 楼

番石榴的ComparisonChain提供了一种干净的方法。请参阅此链接。

用于执行链式比较语句的实用程序。例如:

   public int compareTo(Foo that) {
     return ComparisonChain.start()
         .compare(this.aString, that.aString)
         .compare(this.anInt, that.anInt)
         .compare(this.anEnum, that.anEnum, Ordering.natural().nullsLast())
         .result();
   }


#8 楼

您可以这样做:

List<User> users = Lists.newArrayList(
  new User("Pedro", 12), 
  new User("Maria", 10), 
  new User("Rafael",12)
);

users.sort(
  Comparator.comparing(User::getName).thenComparing(User::getAge)
);


#9 楼

使用Comparator,然后将对象放入Collection,然后放入Collections.sort();

class Person {

    String fname;
    String lname;
    int age;

    public Person() {
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public String getFname() {
        return fname;
    }

    public void setFname(String fname) {
        this.fname = fname;
    }

    public String getLname() {
        return lname;
    }

    public void setLname(String lname) {
        this.lname = lname;
    }

    public Person(String fname, String lname, int age) {
        this.fname = fname;
        this.lname = lname;
        this.age = age;
    }

    @Override
    public String toString() {
        return fname + "," + lname + "," + age;
    }
}

public class Main{

    public static void main(String[] args) {
        List<Person> persons = new java.util.ArrayList<Person>();
        persons.add(new Person("abc3", "def3", 10));
        persons.add(new Person("abc2", "def2", 32));
        persons.add(new Person("abc1", "def1", 65));
        persons.add(new Person("abc4", "def4", 10));
        System.out.println(persons);
        Collections.sort(persons, new Comparator<Person>() {

            @Override
            public int compare(Person t, Person t1) {
                return t.getAge() - t1.getAge();
            }
        });
        System.out.println(persons);

    }
}


#10 楼

根据需要创建尽可能多的比较器。之后,为每个订单类别调用方法“ thenComparing”。这是Streams的一种实现方式。请参阅:

//Sort by first and last name
System.out.println("\n2.Sort list of person objects by firstName then "
                                        + "by lastName then by age");
Comparator<Person> sortByFirstName 
                            = (p, o) -> p.firstName.compareToIgnoreCase(o.firstName);
Comparator<Person> sortByLastName 
                            = (p, o) -> p.lastName.compareToIgnoreCase(o.lastName);
Comparator<Person> sortByAge 
                            = (p, o) -> Integer.compare(p.age,o.age);

//Sort by first Name then Sort by last name then sort by age
personList.stream().sorted(
    sortByFirstName
        .thenComparing(sortByLastName)
        .thenComparing(sortByAge)
     ).forEach(person->
        System.out.println(person));        


外观:在多个字段上对用户定义的对象进行排序–比较器(lambda流)

#11 楼

我在使用Guava的ComparisonChain时会非常小心,因为它会为每个被比较的元素创建一个它的实例,因此您将查看N x Log N比较链的创建,以比较是否要排序,或者如果要迭代并检查是否相等则比较N实例。 。

如果可能的话,我会使用最新的Java 8 API或Guava的Comparator API创建一个静态的Ordering,Java的示例如下:

import java.util.Comparator;
import static java.util.Comparator.naturalOrder;
import static java.util.Comparator.nullsLast;

private static final Comparator<Person> COMPARATOR = Comparator
  .comparing(Person::getName, nullsLast(naturalOrder()))
  .thenComparingInt(Person::getAge);

@Override
public int compareTo(@NotNull Person other) {
  return COMPARATOR.compare(this, other);
}


这里是如何使用番石榴的Ordering API:https://github.com/google/guava/wiki/OrderingExplained

评论


“ ...为每个被比较的元素创建它的一个实例...”-这是不正确的。至少在现代版本的Guava中,调用compare方法不会创建任何内容,而是根据比较结果返回LESS,GREATTER或ACTIVE的单例实例之一。这是一种高度优化的方法,不会增加任何内存或性能开销。

– Yoy N.
19年5月22日在9:51

是;现在,我只是看了一下源代码,明白了你的意思,但是我更倾向于为了依赖而使用新的Java 8比较API。

–圭多麦地那(Guido Medina)
19年5月23日在14:36

#12 楼

或者,您可以利用以下事实:Collections.sort()(或Arrays.sort())是稳定的(它不会对相等的元素进行重新排序),然后使用Comparator首先按年龄排序,然后再使用另一个对名称进行排序。

在这种特定情况下,这不是一个好主意,但是如果您必须能够在运行时更改排序顺序,则可能会很有用。

#13 楼

您可以使用通用串行比较器按多个字段对集合进行排序。

import org.apache.commons.lang3.reflect.FieldUtils;
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;

/**
* @author MaheshRPM
*/
public class SerialComparator<T> implements Comparator<T> {
List<String> sortingFields;

public SerialComparator(List<String> sortingFields) {
    this.sortingFields = sortingFields;
}

public SerialComparator(String... sortingFields) {
    this.sortingFields = Arrays.asList(sortingFields);
}

@Override
public int compare(T o1, T o2) {
    int result = 0;
    try {
        for (String sortingField : sortingFields) {
            if (result == 0) {
                Object value1 = FieldUtils.readField(o1, sortingField, true);
                Object value2 = FieldUtils.readField(o2, sortingField, true);
                if (value1 instanceof Comparable && value2 instanceof Comparable) {
                    Comparable comparable1 = (Comparable) value1;
                    Comparable comparable2 = (Comparable) value2;
                    result = comparable1.compareTo(comparable2);
                } else {
                    throw new RuntimeException("Cannot compare non Comparable fields. " + value1.getClass()
                            .getName() + " must implement Comparable<" + value1.getClass().getName() + ">");
                }
            } else {
                break;
            }
        }
    } catch (IllegalAccessException e) {
        throw new RuntimeException(e);
    }
    return result;
}
}


#14 楼

Arrays.sort(persons, new PersonComparator());



import java.util.Comparator;

public class PersonComparator implements Comparator<? extends Person> {

    @Override
    public int compare(Person o1, Person o2) {
        if(null == o1 || null == o2  || null == o1.getName() || null== o2.getName() ){
            throw new NullPointerException();
        }else{
            int nameComparisonResult = o1.getName().compareTo(o2.getName());
            if(0 == nameComparisonResult){
                return o1.getAge()-o2.getAge();
            }else{
                return nameComparisonResult;
            }
        }
    }
}


class Person{
    int age; String name;

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

}


更新版本:

public class PersonComparator implements Comparator<? extends Person> {

   @Override
   public int compare(Person o1, Person o2) {

      int nameComparisonResult = o1.getName().compareToIgnoreCase(o2.getName());
      return 0 == nameComparisonResult?o1.getAge()-o2.getAge():nameComparisonResult;

   }
 }


评论


nullpointer异常处理非常好,并明确说明它不适用于null,但无论如何都会引发它

–拉尔夫
2011年1月26日14:43

你是绝对正确的。我最近曾经检查过一些要从一个地方复制到另一个地方的值,现在我一直在各处做它。

–fmucar
2011年1月26日15:47

#15 楼

对于这样的类Book

package books;

public class Book {

    private Integer id;
    private Integer number;
    private String name;

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public Integer getNumber() {
        return number;
    }

    public void setNumber(Integer number) {
        this.number = number;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @Override
    public String toString() {
        return "book{" +
                "id=" + id +
                ", number=" + number +
                ", name='" + name + '\'' + '\n' +
                '}';
    }
}


用模拟对象对主类进行排序

package books;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;


public class Main {

    public static void main(String[] args) {
        System.out.println("Hello World!");

        Book b = new Book();

        Book c = new Book();

        Book d = new Book();

        Book e = new Book();

        Book f = new Book();

        Book g = new Book();
        Book g1 = new Book();
        Book g2 = new Book();
        Book g3 = new Book();
        Book g4 = new Book();




        b.setId(1);
        b.setNumber(12);
        b.setName("gk");

        c.setId(2);
        c.setNumber(12);
        c.setName("gk");

        d.setId(2);
        d.setNumber(13);
        d.setName("maths");

        e.setId(3);
        e.setNumber(3);
        e.setName("geometry");

        f.setId(3);
        f.setNumber(34);
        b.setName("gk");

        g.setId(3);
        g.setNumber(11);
        g.setName("gk");

        g1.setId(3);
        g1.setNumber(88);
        g1.setName("gk");
        g2.setId(3);
        g2.setNumber(91);
        g2.setName("gk");
        g3.setId(3);
        g3.setNumber(101);
        g3.setName("gk");
        g4.setId(3);
        g4.setNumber(4);
        g4.setName("gk");





        List<Book> allBooks = new ArrayList<Book>();

        allBooks.add(b);
        allBooks.add(c);
        allBooks.add(d);
        allBooks.add(e);
        allBooks.add(f);
        allBooks.add(g);
        allBooks.add(g1);
        allBooks.add(g2);
        allBooks.add(g3);
        allBooks.add(g4);



        System.out.println(allBooks.size());


        Collections.sort(allBooks, new Comparator<Book>() {

            @Override
            public int compare(Book t, Book t1) {
                int a =  t.getId()- t1.getId();

                if(a == 0){
                    int a1 = t.getNumber() - t1.getNumber();
                    return a1;
                }
                else
                    return a;
            }
        });
        System.out.println(allBooks);

    }


   }


#16 楼

我不确定在这种情况下在Person类中编写比较器是否难看。像这样吗:

public class Person implements Comparable <Person> {

    private String lastName;
    private String firstName;
    private int age;

    public Person(String firstName, String lastName, int BirthDay) {
        this.firstName = firstName;
        this.lastName = lastName;
        this.age = BirthDay;
    }

    public int getAge() {
        return age;
    }

    public String getFirstName() {
        return firstName;
    }

    public String getLastName() {
        return lastName;
    }

    @Override
    public int compareTo(Person o) {
        // default compareTo
    }

    @Override
    public String toString() {
        return firstName + " " + lastName + " " + age + "";
    }

    public static class firstNameComperator implements Comparator<Person> {
        @Override
        public int compare(Person o1, Person o2) {
            return o1.firstName.compareTo(o2.firstName);
        }
    }

    public static class lastNameComperator implements Comparator<Person> {
        @Override
        public int compare(Person o1, Person o2) {
            return o1.lastName.compareTo(o2.lastName);
        }
    }

    public static class ageComperator implements Comparator<Person> {
        @Override
        public int compare(Person o1, Person o2) {
            return o1.age - o2.age;
        }
    }
}
public class Test {
    private static void print() {
       ArrayList<Person> list = new ArrayList();
        list.add(new Person("Diana", "Agron", 31));
        list.add(new Person("Kay", "Panabaker", 27));
        list.add(new Person("Lucy", "Hale", 28));
        list.add(new Person("Ashley", "Benson", 28));
        list.add(new Person("Megan", "Park", 31));
        list.add(new Person("Lucas", "Till", 27));
        list.add(new Person("Nicholas", "Hoult", 28));
        list.add(new Person("Aly", "Michalka", 28));
        list.add(new Person("Adam", "Brody", 38));
        list.add(new Person("Chris", "Pine", 37));
        Collections.sort(list, new Person.lastNameComperator());
        Iterator<Person> it = list.iterator();
        while(it.hasNext()) 
            System.out.println(it.next().toString()); 
     }  
}    


评论


确实不建议将模式绑定到特定的比较器。

–Georgios Stathis
7小时前