繁体   English   中英

比较两个列表并获得差异

[英]Comparing two lists and getting differences

我有两个清单。 它们包含不同类型的对象,但这两种类型都包含id和name,而id是我要比较的。 列表一从DB中获取,列表二从前端发送。

我需要做的是循环它们,找到新添加的列表项和删除的列表项。

我能够做到,但问题是它看起来很难看。

假设我有一个名为NameDTO的对象,它可以有id和name。 列表2填充了该类型的对象。

这就是我做的方式:

final ArrayList<NamedDTO> added = new ArrayList<>();
final ArrayList<NamedDTO> removed = new ArrayList<>();

for(NamedDTO listTwoObject : listTwo) {
   boolean contained = false;
   for(SomeObject listOneObject : listOne) {
       if(listTwoObject.getId().equals(listOneObject.getId()) {
           contained = true;
       }
   }
   if(!contained) {
      added.add(listTwoObject);
   }
}

for(SomeObject listOneObject : listOne) {
   boolean contained = false;
   for(NamedDTO listTwoObject : listTwo) {
       if(listTwoObject.getId().equals(listOneObject.getId()) {
           contained = true;
       }
   }
   if(!contained) {
      removed.add(new NamedDTO(listOneObject.getId(), listOneObject.getName()));
  }
}

这有效,我已经测试过了。 有更好的解决方案吗? 我正在考虑使用套装,所以我可以比较它们,这有什么缺点吗?

如果我理解正确,这是示例场景:

  • listOne [datab]项目: [A, B, C, D]
  • listTwo [front]项目: [B, C, D, E, F]

你需要得到的效果是:

  • 补充: [E, F]
  • 删除: [A]

首先,我会使用某种类型的适配器或从一个公共类扩展不同的类型并override equals方法,以便您可以通过idname匹配它们

其次,这是非常简单的集合操作(​​你可以使用set,但列表也很好)。 我建议使用库: https//commons.apache.org/proper/commons-collections/apidocs/org/apache/commons/collections4/CollectionUtils.html

现在基本上:

  • 添加的是listTwo - listOne
  • 删除是listOne - listTwo

并使用java代码:

  • 补充: CollectionUtils.removeAll(listTwo, listOne)
  • 已删除: CollectionUtils.removeAll(listOne, listTwo)

否则,实现CollectionJava Docs )的所有集合也都有removeAll方法,您可以使用它。

我建议使用java 8流解决方案:

    ArrayList<ObjOne> list = new ArrayList<>(Arrays.asList(new ObjOne("1","1"),new ObjOne("3","3"),new ObjOne("2","2")));
    ArrayList<ObjTwo> list2 = new ArrayList<>(Arrays.asList(new ObjTwo("1","1"),new ObjTwo("3","3"),new ObjTwo("4","4")));

    List<ObjOne> removed = list.stream().filter(o1 -> list2.stream().noneMatch(o2 -> o2.getId().equals(o1.getId())))
            .collect(Collectors.toList());
    System.out.print("added ");
    removed.forEach(System.out::println);

    List<ObjTwo> added = list2.stream().filter(o1 -> list.stream().noneMatch(o2 -> o2.getId().equals(o1.getId())))
             .collect(Collectors.toList());

    System.out.print("removed ");
    added.forEach(System.out::println);

这基本上是您的解决方案,但使用流实现,这将使您的代码更短,更易于阅读

这种嵌套列表处理不仅难看,而且效率低下。 最好将一个列表的ID存储到允许高效查找的Set ,然后使用Set处理另一个列表。 这样,您不会执行list1.size()list2.size()操作,而是执行list1.size()list2.size()操作,这对于较大的列表来说是一个显着的区别。 然后,由于两个操作基本相同,因此值得将它们抽象为一个方法:

public static <A,B,R,ID> List<R> extract(
    List<A> l1, List<B> l2, Function<A,ID> aID, Function<B,ID> bID, Function<A,R> r) {

    Set<ID> b=l2.stream().map(bID).collect(Collectors.toSet());
    return l1.stream().filter(a -> !b.contains(aID.apply(a)))
             .map(r).collect(Collectors.toList());
}

这种方法可以用作

List<NamedDTO> added   = extract(listTwo, listOne, NamedDTO::getId, SomeObject::getId,
                                 Function.identity());
List<NamedDTO> removed = extract(listOne, listTwo, SomeObject::getId, NamedDTO::getId,
                                 so -> new NamedDTO(so.getId(), so.getName()));

由于交换两个列表需要辅助方法独立于元素类型,因此它需要访问id属性的函数,可以通过方法引用指定。 然后,需要一个描述结果元素的函数,它是一种情况下的一个标识函数(只是获取NamedDTO )和另一种情况下从SomeObject构造一个NamedDTO的lambda表达式。

操作本身如上所述一样直接,迭代一个列表,映射到id并收集到一个Set ,然后迭代另一个列表,只保留id不在集合中的元素,映射到结果输入并收集到List

如果这些id是唯一的,你可以把它们放在一个HashSet中,找到你感兴趣的id:

    Set<Integer> uiList = Stream.of(new FromUI(1, "db-one"), new FromUI(2, "db-two"), new FromUI(3, "db-three"))
            .map(FromUI::getId)
            .collect(Collectors.toCollection(HashSet::new));
    Set<Integer> dbList = Stream.of(new FromDB(3, "ui-one"), new FromDB(5, "ui-five"))
            .map(FromDB::getId)
            .collect(Collectors.toCollection(HashSet::new));

    uiList.removeIf(dbList::remove);

added/uiSet :   [1,2]
removed/dbSet : [5]

我已经使用构造函数创建了FromUIFromDB类,该构造函数将id和name作为输入。

我还假设如果一个元素包含在uiSet ,但是在dbSet中没有添加, dbSet

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM