如何有效比较两个产品列表

时间:2020-04-10 16:23:30

标签: java algorithm performance data-structures hash

我正在尝试编写一种方法,该方法可以高效地检查两个产品列表是否相等。

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

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

约束条件

  • 同一产品可以在列表中多次出现。例如(产品A,产品B,产品A,产品C)
    如果我使用HashSet存储第一个列表的内容,然后解析第二个列表以检查每个产品是否在集合中,则这可能表示一个问题。因为我不能在HashSet中放置重复项。
  • 如果两个列表包含相同的产品并且出现相同的次数但顺序不相关,则认为这两个列表是相等的。
    例如,这两个列表
    (产品A,产品B ,产品A,产品C)
    (产品C,产品A,产品A,产品B)
    被认为是相等的。

    但那两个
    (产品A ,产品B,产品A,产品C)
    (产品A,产品B,产品C)
    被认为是不同的
  • 对象Product的定义如下(请注意,它的代码是自动生成的,因此我不能在其类内编写方法 equals hashcode

    class Product {
        private String name;
        private Integer quantity;
        private List<Discount> discountsList;
    
        //some other field not needed for the comparison
    }
    
  • 如果两个产品具有相同的名称,相同的数量和相同的折扣列表

    ,则视为相等
  • 对于折扣比较列表,元素的顺序也不相关

  • 像这样定义折扣(同样在这种情况下,该类是自动生成的,我无法编写方法 equals hashcode

    class Discount {
        String code;
    
        //some other field not needed for the comparison
    }
    
  • 如果两个折扣具有相同的代码,则被视为相等

要求和偏好

  • 比较必须高效(我想我必须使用某种哈希)

  • 代码应尽可能简洁(我宁愿避免使用诸如反射之类的东西来解析结构等)

  • 如果可能的话,我宁愿不使用外部库

我的方法(无效:()有效
我开始写一个可能的解决方案的草稿,但是我发现我的方法遇到了不同的障碍,我不知道是否应该以某种方式改进它或完全重新考虑它。
我的想法是扩展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;
  }
}

这种方法显然行不通,因为在没有定义equals和hashCode方法的情况下比较了Discount对象,但是由于在Product对象中定义的DiscountList是Discount类型,所以我无法扩展Discount,所以我不能使用ComparableDiscount最终创建。
此外,一旦定义了哈希机制,我就不知道确切地使用什么最佳方法/数据结构,以检查两个列表是否相等

您能帮我以最好的方式完成这部分代码吗?

1 个答案:

答案 0 :(得分:0)

最简单的方法是编写一个接受Product并生成其唯一字符串表示形式的函数。确保如果您认为两个相同,则必须得到相同的字符串。 (例如,对折扣代码进行排序。)

现在,您可以将List个对象中的一个Product转换为一个List个字符串。现在,您可以轻松比较其中两个列表。

如果这些建议可能很大,一个技巧是实际使用描述的MD5哈希而不是描述本身。这些将更短,并且发生碰撞的几率在天文学上较低。

如果要真正识别差异,则应将代表产品的字符串映射存储到产品对象。这样,一旦您知道一个列表中有哪些字符串,而又不知道其他列表中的字符串,则可以在返回它们之前将它们变回对象。