How to compare objects by multiple fields

后端 未结 22 2559
暖寄归人
暖寄归人 2020-11-22 00:43

Assume you have some objects which have several fields they can be compared by:

public class Person {

    private String firstName;
    private String lastN         


        
22条回答
  •  长情又很酷
    2020-11-22 01:14

    For those able to use the Java 8 streaming API, there is a neater approach that is well documented here: Lambdas and sorting

    I was looking for the equivalent of the C# LINQ:

    .ThenBy(...)
    

    I found the mechanism in Java 8 on the Comparator:

    .thenComparing(...)
    

    So here is the snippet that demonstrates the algorithm.

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

    Check out the link above for a neater way and an explanation about how Java's type inference makes it a bit more clunky to define compared to LINQ.

    Here is the full unit test for reference:

    @Test
    public void testChainedSorting()
    {
        // Create the collection of people:
        ArrayList 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 comparator = Comparator.comparing(person -> person.name);
        comparator = comparator.thenComparing(Comparator.comparing(person -> person.age));
    
        // Sort the stream:
        Stream personStream = people.stream().sorted(comparator);
    
        // Make sure that the output is as expected:
        List 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);
        }
    }
    

提交回复
热议问题