Как вернуть false, если java-коллекция содержит два одинаковых элемента

У меня есть Collection<Event>. Event выглядит примерно так

public class Event {

   private Integer id;
   private LocalDateTime localDateTime;

   // getters, setters omitted

}

Каждый Event в этом Collection должен иметь уникальные id и localDateTime. Как я могу выполнить эту проверку с помощью потокового API и вернуть true, если условие выполнено?

Как реализованы equals() и hashCode()? Они полагаются исключительно на эти два свойства?

Robby Cornelissen 11.06.2019 09:59

^^ иметь уникальные id и localDateTime... уникальные значения каждого из них или обоих в комбинации?

Naman 11.06.2019 10:01

Поиск того, имеет ли итерируемый объект 2 одинаковых элемента, имеет ту же сложность, что и его сортировка O (n log n). Таким образом, либо вы держите помощника HashSet для проверки членства, пока вы выполняете итерацию по нему, чтобы достичь амортизированной сложности O (n), либо вы просто сортируете его и выполняете итерацию, «застегивая» каждый элемент на следующий и проверяя на равенство.

Giacomo Alzetta 11.06.2019 10:02

@Naman уникальные значения каждого из них.

Roshan Upreti 11.06.2019 10:03

@downvoter Не могли бы вы пояснить, почему мой вопрос бесполезен?

Roshan Upreti 17.06.2019 13:36
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
3
5
112
4
Перейти к ответу Данный вопрос помечен как решенный

Ответы 4

 import java.util.concurrent.atomic.AtomicInteger;
    public class Event {

       private static final AtomicInteger idGenerator = new AtomicInteger(1000);
       private Integer id;
       private LocalDateTime localDateTime;

       public Event(){
          id = idGenerator.getAndIncrement();
       }
       // getters, setters omitted
}

Тест кода

public class Test {
    public static void main(String[] args) {
        for(int i = 0; i < 10; ++ i){
            System.out.println(new Event().getId());
        }
    }
}

Выход

1000 1001 1002 1003 1004 1005 1006 1007 1008 1009

Прежде всего, переопределите методы equals() и hashcode() и напишите так:

@Override
public boolean equals(Object o){
if (o instanceof Event){
    Event e = (Event) o;
    return e.id.equals(this.id) && e.localDateTime.equals(this.localDateTime);
}
else return false;
}

@Override
public int hashCode(){
return Objects.hash(id,localDateTime); //this is the default implementation, up to you to implement it in a better way
}

Затем вы можете использовать такой поток, чтобы проверить наличие дубликатов:

public boolean checkAllUnique(Collection<Event> col){
    return col.stream().allMatch(new HashSet<>()::add);
}

Вы правы, про актерский состав забыл, сейчас поправлю

vc73 12.06.2019 09:17
Ответ принят как подходящий

Вы можете использовать два HashSet в качестве резервных коллекций для хранения уникальных элементов и перебирать список событий следующим образом:

public boolean duplicateExists(List<Event> eventList) {
    Set<Integer> ids = new HashSet<>();
    Set<LocalDateTime> localDateTimes = new HashSet<>();
    return eventList.stream()
            .anyMatch(event -> !ids.add(event.getId()) ||
                    !localDateTimes.add(event.getLocalDateTime()));
}

Поскольку Integer и LocalDateTime никогда не могут конфликтовать, здесь не нужны два HashSet, достаточно одного HashSet<Object>. Но я бы использовал петлю вместо Stream здесь.

Holger 11.06.2019 17:49

Это класс Event, который вам понадобится;

class Event {

    private Integer id;

    private LocalDateTime localDateTime;

    public Integer getId() {
        return id;
    }

    public LocalDateTime getLocalDateTime() {
        return localDateTime;
    }

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

    public void setLocalDateTime(LocalDateTime localDateTime) {
        this.localDateTime = localDateTime;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Event event = (Event) o;
        return id.equals(event.id) &&
                localDateTime.equals(event.localDateTime);
    }

    @Override
    public int hashCode() {
        return Objects.hash(id, localDateTime);
    }

    public static boolean hasDuplicates(List<Event> events) {
        /*
            return events
            .stream()
            .noneMatch(e -> events
                    .stream()
                    .filter(ev -> ev.equals(e)).count() > 1);
         */
         return events.stream()
             .distinct()
             .count() != events.size(); // Kudos to @Holger for this approach.
    }
}

Эта hasDuplicates является static функцией, поэтому она никак не повлияет на создание вашего объекта. Однако вы можете использовать его как вспомогательный метод для проверки дубликатов. Вам понадобится только одна строка проверки.

Большое спасибо, что нашли время для фрагмента. Я был немного незнаком с этим методом. Теперь, я думаю, у меня есть некоторое понимание того, как это работает.

Roshan Upreti 11.06.2019 10:38

Я думаю, у вас есть эта путаница из-за реализации .equals и .hashCode. Обратитесь к этому, чтобы иметь некоторое понимание -> journaldev.com/21095/java-equals-hashcode. Большинство основных реализаций Java основано на этих двух методах. Если вы переопределили эти два метода (переопределить обе функции являются обязательными, поэтому равенство — контракт хэш-кода), вы можете просто вызвать event1.equals(event2) для своих объектов. Поэтому здесь также работает функция containes().

Sachith Dickwella 11.06.2019 10:54

Этот код ерунда. Вы просматриваете элементы в списке, чтобы убедиться, что ни один из этих элементов не содержится в этом списке, что является противоречием. Единственный раз, когда hasDuplicates вернет true, это когда ему дан пустой список.

Ben R. 11.06.2019 10:59

Потоковая передача по List для повторной передачи по списку для каждого элемента приведет к ужасной производительности (также известной как квадратичная временная сложность). Почему вы не используете return events .stream() .distinct() .count() != events.size();?

Holger 11.06.2019 17:53

@Holger, вау, это отличный подход. Это никогда не приходило мне в голову.

Sachith Dickwella 11.06.2019 18:29

Другие вопросы по теме