【问题标题】:Java - find differences between lists of objectsJava - 查找对象列表之间的差异
【发布时间】:2023-01-07 01:44:59
【问题描述】:

在 Java 11+ 中,是否有一种优雅的方法来查找 2 个对象列表之间的差异? 过滤应该在一个简单的 col1 值对象的一个​​“值”属性上完成。通常该对象将包含至少 2 个其他属性。

假设我有这两个列表:

  • 列表 1:({“左”,“一”},{“左”,“二”})
  • 列表 2:({“右”,“二”},{“右”,“三”})

结果应该是一个列表:

  • ({“左”,“一”},{“右”,“三”})

当然,有一种简单的旧方法可以做到这一点。这个简单的程序给出:

ColValueObject{base='left', value='Value one'} ColValueObject{base='right', value='Value four'}

public class CompareListOfObjects {
  public static void main(String[] args) {
    List<ColValueObject> list1 = List.of(
            new ColValueObject("left", "Value one"),
            new ColValueObject("left", "Value two"),
            new ColValueObject("left", "Value three"));
    List<ColValueObject> list2 = List.of(
            new ColValueObject("right", "Value two"),
            new ColValueObject("right", "Value three"),
            new ColValueObject("right", "Value four"));

    List<ColValueObject> result = findDifferencesBetweenLists(list1, list2);
    result.forEach(System.out::println);
  }

  private static List<ColValueObject> findDifferencesBetweenLists(List<ColValueObject> list1, List<ColValueObject> list2) {
    List<ColValueObject> result = new ArrayList<>();
    findUniqueEntriesInList((List<ColValueObject>) list1, (List<ColValueObject>) list2, (List<ColValueObject>) result);
    findUniqueEntriesInList((List<ColValueObject>) list2, (List<ColValueObject>) list1, (List<ColValueObject>) result);
    return result;
  }

  private static void findUniqueEntriesInList(List<ColValueObject> list1, List<ColValueObject> list2, List<ColValueObject> result) {
    for (ColValueObject l1 : list1) {
      boolean found = false;
      for (ColValueObject l2 : list2) {
        if (l1.getValue().equals(l2.getValue())) {
          found = true;
          break;
        }
      }
      if (!found) {
        result.add(l1);
      }
    }
  }
}

class ColValueObject {
  private String base;
  private String value;

  public ColValueObject(String base, String value) {
    this.base = base;
    this.value = value;
  }

  public String getBase() {
    return base;
  }

  public void setBase(String base) {
    this.base = base;
  }

  public String getValue() {
    return value;
  }

  public void setValue(String value) {
    this.value = value;
  }

  @Override
  public String toString() {
    return "ColValueObject{" +
            "base='" + base + '\'' +
            ", value='" + value + '\'' +
            '}';
  }
}

【问题讨论】:

  • 请准确描述“差异”结果是如何确定的以及您的代码有什么“错误”。

标签: java


【解决方案1】:

您可以覆盖ColValueObject 类型的equals 方法,这样您就可以仅通过value 匹配这些对象。

然后我建议使用 removeAll 方法,它在任何实现 Collection (Java Doc) 的集合中或在 CollectionUtils 库中。

基本上你会有两个结果列表:

List<ColValueObject> result1 = CollectionUtils.removeAll(list2, list1);
List<ColValueObject> result2 = CollectionUtils.removeAll(list1, list2);

最后可以使用addAll方法得到最终的结果列表。

【讨论】:

    【解决方案2】:

    看起来这是一个非常简单的算法。您所需要做的就是按值对所有对象进行分组(即创建一个Map)并仅检索这些对象,这些对象对于给定的键是单个的。

    public static List<ColValueObject> getUnique(List<ColValueObject> one,
                                                 List<ColValueObject> two) {
        Map<String, List<ColValueObject>> map = new HashMap<>();
    
        Stream.of(one, two)
              .flatMap(List::stream)
              .forEach(obj -> map.compute(obj.getValue(), (key, objs) -> {
                  objs = Optional.ofNullable(objs).orElseGet(ArrayList::new);
                  objs.add(obj);
                  return objs;
              }));
    
        return map.values().stream()
                  .filter(objs -> objs.size() == 1)
                  .map(objs -> objs.get(0))
                  .collect(Collectors.toList());
    }
    

    【讨论】:

      【解决方案3】:

      您可以首先按每个对象的速率对列表进行分组并计算出现次数,如果出现次数等于 1,则第二次过滤结果流。之后,您必须将 EntrySet 的第一个对象映射到 ColValueObject 并收集最终列表。

      List<ColValueObject> result = Stream.of(list1, 
      list2).flatMap(List::stream).collect(groupingBy(d -> d.getValue())).entrySet().stream().filter(e -> e.getValue().size() == 1).map(e -> e.getValue().get(0)).collect(Collectors.toList());
          System.out.println(result);
      

      要使用它,需要以下静态导入:

      import static java.util.stream.Collectors.groupingBy;
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2013-02-08
        • 2011-01-24
        • 1970-01-01
        • 1970-01-01
        • 2013-06-27
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多