Как сравнивать объекты по нескольким полям - PullRequest
190 голосов
/ 15 декабря 2008

Предположим, у вас есть несколько объектов, у которых есть несколько полей, с которыми они могут сравниваться:

public class Person {

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

    /* Constructors */

    /* Methods */

}

Так что в этом примере, когда вы спрашиваете:

a.compareTo(b) > 0

возможно, вы спрашиваете, стоит ли фамилия a перед буквой b, или если a старше b и т. Д. *

Каков самый чистый способ включить множественное сравнение между этими типами объектов без добавления ненужных помех или накладных расходов?

  • java.lang.Comparable интерфейс позволяет сравнивать только по одному полю
  • Добавление многочисленных методов сравнения (т. Е. compareByFirstName(), compareByAge() и т. Д.), На мой взгляд, загромождено.

Так, как лучше всего это сделать?

Ответы [ 21 ]

4 голосов
/ 15 декабря 2008

Вместо методов сравнения вы можете просто определить несколько типов подклассов "Comparator" внутри класса Person. Таким образом, вы можете передать их в стандартные методы сортировки коллекций.

2 голосов
/ 15 декабря 2008

Если есть несколько способов, которыми пользователь может заказать человека, вы также можете иметь несколько Comparator s настроек в качестве констант где-нибудь. Большинство операций сортировки и отсортированных коллекций принимают в качестве параметра компаратор.

2 голосов
/ 15 декабря 2008

Я думаю, было бы более запутанным, если бы ваш алгоритм сравнения был "умным". Я бы пошел с многочисленными методами сравнения, которые вы предложили.

Единственным исключением для меня было бы равенство. Для модульного тестирования мне было полезно переопределить .Equals (в .net), чтобы определить, равны ли несколько полей между двумя объектами (а не равны ли ссылки).

1 голос
/ 22 ноября 2017

Легко сравнить два объекта методом хеш-кода в java`

public class Sample{

  String a=null;
  String b=null;

  public Sample(){
      a="s";
      b="a";
  }
  public Sample(String a,String b){
      this.a=a;
      this.b=b;
  }
  public static void main(String args[]){
      Sample f=new Sample("b","12");
      Sample s=new Sample("b","12");
      //will return true
      System.out.println((s.a.hashCode()+s.b.hashCode())==(f.a.hashCode()+f.b.hashCode()));

      //will return false
      Sample f=new Sample("b","12");
      Sample s=new Sample("b","13");
      System.out.println((s.a.hashCode()+s.b.hashCode())==(f.a.hashCode()+f.b.hashCode()));

}
1 голос
/ 24 июня 2014
//here threshold,buyRange,targetPercentage are three keys on that i have sorted my arraylist 
final Comparator<BasicDBObject> 

    sortOrder = new Comparator<BasicDBObject>() {
                    public int compare(BasicDBObject e1, BasicDBObject e2) {
                        int threshold = new Double(e1.getDouble("threshold"))
                        .compareTo(new Double(e2.getDouble("threshold")));
                        if (threshold != 0)
                            return threshold;

                        int buyRange = new Double(e1.getDouble("buyRange"))
                        .compareTo(new Double(e2.getDouble("buyRange")));
                        if (buyRange != 0)
                            return buyRange;

                        return (new Double(e1.getDouble("targetPercentage")) < new Double(
                                e2.getDouble("targetPercentage")) ? -1 : (new Double(
                                        e1.getDouble("targetPercentage")) == new Double(
                                                e2.getDouble("targetPercentage")) ? 0 : 1));
                    }
                };
                Collections.sort(objectList, sortOrder);
0 голосов
/ 26 июня 2018

Обычно я перезаписываю свой метод compareTo() таким образом, когда мне приходится выполнять многоуровневую сортировку.

public int compareTo(Song o) {
    // TODO Auto-generated method stub
    int comp1 = 10000000*(movie.compareTo(o.movie))+1000*(artist.compareTo(o.artist))+songLength;
    int comp2 = 10000000*(o.movie.compareTo(movie))+1000*(o.artist.compareTo(artist))+o.songLength;
    return comp1-comp2;
} 

Здесь в первую очередь предпочтение отдается названию фильма, а затем исполнителю и, наконец, songLength. Вы просто должны убедиться, что эти множители достаточно далеко, чтобы не пересекать границы друг друга.

0 голосов
/ 06 мая 2018
//Following is the example in jdk 1.8
package com;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;

class User {
    private String firstName;
    private String lastName;
    private Integer age;

    public Integer getAge() {
        return age;
    }

    public User setAge(Integer age) {
        this.age = age;
        return this;
    }

    public String getFirstName() {
        return firstName;
    }

    public User setFirstName(String firstName) {
        this.firstName = firstName;
        return this;
    }

    public String getLastName() {
        return lastName;
    }

    public User setLastName(String lastName) {
        this.lastName = lastName;
        return this;
    }

}

public class MultiFieldsComparision {

    public static void main(String[] args) {
        List<User> users = new ArrayList<User>();

        User u1 = new User().setFirstName("Pawan").setLastName("Singh").setAge(38);
        User u2 = new User().setFirstName("Pawan").setLastName("Payal").setAge(37);
        User u3 = new User().setFirstName("Anuj").setLastName("Kumar").setAge(60);
        User u4 = new User().setFirstName("Anuj").setLastName("Kumar").setAge(43);
        User u5 = new User().setFirstName("Pawan").setLastName("Chamoli").setAge(44);
        User u6 = new User().setFirstName("Pawan").setLastName("Singh").setAge(5);

        users.add(u1);
        users.add(u2);
        users.add(u3);
        users.add(u4);
        users.add(u5);
        users.add(u6);

        System.out.println("****** Before Sorting ******");

        users.forEach(user -> {
            System.out.println(user.getFirstName() + " , " + user.getLastName() + " , " + user.getAge());
        });

        System.out.println("****** Aftre Sorting ******");

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

        users.forEach(user -> {
            System.out.println(user.getFirstName() + " , " + user.getLastName() + " , " + user.getAge());
        });

    }

}
0 голосов
/ 21 марта 2017

Начиная с Ответ Стива Можно использовать троичный оператор:

public int compareTo(Person other) {
    int f = firstName.compareTo(other.firstName);
    int l = lastName.compareTo(other.lastName);
    return f != 0 ? f : l != 0 ? l : Integer.compare(age, other.age);
}
0 голосов
/ 09 декабря 2015

В блоге приведен пример цепочки компараторов

http://www.codejava.net/java-core/collections/sorting-a-list-by-multiple-attributes-example

import java.util.Arrays;
import java.util.Comparator;
import java.util.List;

/**
 * This is a chained comparator that is used to sort a list by multiple
 * attributes by chaining a sequence of comparators of individual fields
 * together.
 *
 */
public class EmployeeChainedComparator implements Comparator<Employee> {

    private List<Comparator<Employee>> listComparators;

    @SafeVarargs
    public EmployeeChainedComparator(Comparator<Employee>... comparators) {
        this.listComparators = Arrays.asList(comparators);
    }

    @Override
    public int compare(Employee emp1, Employee emp2) {
        for (Comparator<Employee> comparator : listComparators) {
            int result = comparator.compare(emp1, emp2);
            if (result != 0) {
                return result;
            }
        }
        return 0;
    }
}

Вызывающий компаратор:

Collections.sort(listEmployees, new EmployeeChainedComparator(
                new EmployeeJobTitleComparator(),
                new EmployeeAgeComparator(),
                new EmployeeSalaryComparator())
        );
0 голосов
/ 16 декабря 2008

Если вы реализуете Comparable интерфейс, вам нужно выбрать одно простое свойство для упорядочения. Это известно как естественный порядок. Думайте об этом как о умолчанию. Он всегда используется, когда нет конкретного компаратора. Обычно это имя, но ваш вариант использования может потребовать чего-то другого. Вы можете использовать любое количество других компараторов, которые вы можете предоставить различным API коллекций, чтобы переопределить естественный порядок.

Также обратите внимание, что обычно если a.compareTo (b) == 0, то a.equals (b) == true. Это нормально, если нет, но есть побочные эффекты, о которых нужно знать. Посмотрите превосходные javadocs на интерфейсе Comparable, и вы найдете много полезной информации об этом.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...