получить список объектов, различающихся по всем полям [дубликат]

avatar
Nazerke
8 апреля 2018 в 09:28
183
2
-1

Как я могу получить все отдельные объекты в списке, используя потоки Java 8? Он должен сравнивать все поля объектов друг с другом. Например

Person a = Person("nameA", "35") и Person b = Person("nameA", "35")

должно быть равно. То, что я пытался personList.stream().distinct().collect(Collectors.toList()), возвращает список из 2 человек, а не только 1.

Источник
Eran
8 апреля 2018 в 09:29
4

Ваш класс Person должен переопределять equals.

Szymon Stepniak
8 апреля 2018 в 09:55
0

dzone.com/articles/working-with-hashcode-and-equals-in-java

Nazerke
8 апреля 2018 в 11:31
0

@Eran Я пытался переопределить equals, но похоже, что Different() не использует equals(), потому что он не работает. Спасибо за предложение

Ousmane D.
8 апреля 2018 в 12:51
1

@Nazerke, скорее всего, вы неправильно переопределили equals и hashcode. Я привел пример в своем ответе.

Ответы (2)

avatar
gil.fernandes
8 апреля 2018 в 09:50
-1

Если вы можете положиться на методы equals и hashCode класса Person, как написал @Eran в комментарии, тогда вы можете использовать свой код, и он будет выполнять свою работу так, как предполагалось. Если по какой-то причине вы не можете изменить класс Person, то вам нужно использовать сборщик с "группировать по" и указать свой ключ.

Вот пример того, как использовать "группировать по" для создания собственного ключа группировки:

Person person1 = new Person("John", "Doe");
Person person2 = new Person("John", "Doe");
Person person3 = new Person("Mary", "Doe");
Person person4 = new Person("Mary", "Doe");
Person person5 = new Person("john", "Smith");
List<Person> persons = Arrays.asList(person1, person2, person3, person4, person5);

// Creates your own equality using "group by". Here we are using first and last name concatenation
final Map<String, List<Person>> collect = persons.stream()
        .collect(Collectors.groupingBy(o -> o.getFirstName() + o.getLastName()));
// Get the values and extract the first element to build a distinct list.
final List<Person> collect1 = collect.values().stream().map(ps -> ps.get(0)).collect(Collectors.toList());
System.out.println(collect1.size());

Выводится:

3
Misha
8 апреля 2018 в 22:26
1

Не рекомендуется группировать путем конкатенации. «Эл» + «Эндрюс» равно «Алан» + «Дрюс». Если вам нужно пойти по этому пути, лучше сгруппироваться по Arrays.asList(first, last).

avatar
Ousmane D.
8 апреля 2018 в 12:50
1

Для получения ожидаемого результата необходимо переопределить equals и hashcode.

Пример:

class Person {
    private String name;
    private String theOtherField; 

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;

        Person person = (Person) o;

        return (name != null ? name.equals(person.name) : person.name == null) && 
                (theOtherField != null ? theOtherField.equals(person.theOtherField) : 
                        person.theOtherField == null);
    }

    @Override
    public int hashCode() {
        int result = name != null ? name.hashCode() : 0;
        result = 31 * result + (theOtherField != null ? theOtherField.hashCode() : 0);
        return result;
    }

    public Person(String name, String theOtherField) {
        this.name = name;
        this.theOtherField = theOtherField;
    }
}

Теперь предположим, что у вас есть список таких людей, например:

 List<Person> personList = Arrays.asList(new Person("nameA", "35"),
               new  Person("nameA", "35"));

Выполнение операции distinct должно дать список с одним элементом.

List<Person> distinctPeople = 
           personList.stream()
                     .distinct()
                     .collect(Collectors.toList());

или вы можете собрать в реализацию Set без использования distinct следующим образом:

 Set<Person> distinctPeople = new HashSet<>(personList);

Обратите внимание, я назвал одно из свойств в классе Person theOtherField, потому что я не знаю, представляет ли оно возраст человека или нет, поскольку в идеале возраст человека должен быть int, а не String.