Как эффективно сравнить два списка продуктов - PullRequest
2 голосов
/ 10 апреля 2020

Я пытаюсь написать метод, который эффективно проверяет, равны ли два списка продуктов.

List<Product> firstList = getProductsListFromSomewhere();
List<Product> secondList = getProductsListFromSomewhereElse();

public boolean areListsEqual(List<Product> firstList, List<Product> secondList) {
    ...
}

Ограничения и условия

  • Один и тот же продукт может появляться в списке несколько раз. Ex. (Продукт A, Продукт B, Продукт A, Продукт C)
    Это может представлять проблему, если я использую HashSet для хранения содержимого первого списка, а затем анализирую второй список, чтобы проверить, присутствует ли каждый Продукт в установить, потому что я не могу поместить дубликаты в HashSet.
  • Два списка считаются равными, если они содержат одинаковые продукты, и они появляются одинаковое количество раз, но их порядок НЕ имеет значения.
    Так что для Например, эти два списка
    (Продукт A, Продукт B, Продукт A, Продукт C)
    (Продукт C, Продукт A, Продукт A, Продукт B)
    считаются равными.

    Но эти два
    (Продукт A, Продукт B, Продукт A, Продукт C)
    (Продукт A, Продукт B, Продукт C)
    считаются различными
  • Объект Product определяется следующим образом (обратите внимание, что его код генерируется автоматически, поэтому я не могу написать методы равно и хэш-код внутри своего класса)

    class Product {
        private String name;
        private Integer quantity;
        private List<Discount> discountsList;
    
        //some other field not needed for the comparison
    }
    
  • Два продукта считаются равными если у них одинаковое имя , одинаковое количество и одинаковое discountList

  • Также для списков скидок Сравнение порядка элемента НЕ имеет значения

  • Скидка определяется следующим образом (также в этом случае класс генерируется автоматически, и я не могу написать методы равно и хэш-код )

    class Discount {
        String code;
    
        //some other field not needed for the comparison
    }
    
  • Две скидки считаются равными, если они имеют одинаковый код

Требования и предпочтения

  • Сравнение должно быть эффективным (думаю, мне нужно использовать какое-то хеширование)

  • код должен быть как можно более чистым (я бы предпочел не использовать такие вещи, как рефлексия, для анализа структуры et c)

  • Если возможно, я бы предпочел НЕ использовать внешние библиотеки

Мой (недействительный :() подход
Я начал писать черновой вариант Это отличное решение, но я нашел разные блокираторы для своего подхода, и я не знаю, следует ли мне каким-то образом его уточнить или полностью переосмыслить.
Моя идея - расширить класс Product внутри класса, который должен выполнять сравнение:

List<Product> firstList = getProductsListFromSomewhere();
List<Product> secondList = getProductsListFromSomewhereElse();

public boolean areListsEqual(List<Product> firstList, List<Product> secondList) {
    ...
}  

private class ComparableProduct extends Product {

  @Override
  public boolean equals(Object obj) {
    if (this == obj) {
      return true;
    }
    if (obj == null) {
      return false;
    }
    if (getClass() != obj.getClass()) {
      return false;
    }
    final ComparableProduct other = (ComparableProduct)obj;
    if (!Objects.equals(this.name, other.name)) {
      return false;
    }
    if (!Objects.equals(this.quantity, other.quantity)) {
      return false;
    }
    if (!Objects.equals(this.discountList, other.discountList)) {
      return false;
    }
    return true;
  }

  @Override
  public int hashCode() {
    int hash = 3;
    hash = 79 * hash + Objects.hashCode(this.name);
    hash = 79 * hash + Objects.hashCode(this.quantity);
    hash = 79 * hash + Objects.hashCode(this.discountList);
    return hash;
  }
}

Этот подход, очевидно, не работает, потому что объект Discount сравнивается без определения методов equals и hashCode, но я не могу расширить Discount, потому что discountList, определенный в объекте Product, имеет тип Discount, поэтому я не может использовать ComparableDiscount, созданный в конце концов.
Более того, я не знаю точно, какой наилучший способ / структуру данных использовать, когда определен механизм хеширования, чтобы проверить, что два списка равны

Не могли бы вы помочь мне завершить эту часть? кода в лучшем виде?

1 Ответ

0 голосов
/ 10 апреля 2020

Самый простой подход - написать функцию, которая принимает Product и генерирует уникальное строковое представление. Убедитесь, что если вы считаете два одинаковых, вы должны получить ту же строку. (Например, сортируйте коды скидок.)

Теперь вы можете превратить List из Product объектов в List строк. Теперь вы можете довольно легко сравнить два из этих списков.

Один совет, если они могут быть большими, - это на самом деле работать с MD5 га sh описания, а не с самим описанием. Они будут короче, а вероятность столкновения астрономически мала.

Если вы хотите на самом деле определить различия, вам следует сохранить карту строки, представляющей продукт, для объекта продукта. Таким образом, когда вы знаете, какие строки находятся в одном списке, а не в другом, вы можете превратить строки обратно в объекты, прежде чем возвращать их.

...