5

在java中假设我有2个列表

List<Object1> list1
List<Object2> list2

object1.getName(); returns a String
object2.getName(); return a String

有什么方法可以比较名称并获得两个列表的差异

这两个对象是在 3rd 方库中定义的,我不能覆盖 equals 和 compareto 方法

我赞成谷歌番石榴或公共收藏图书馆

但是Sets.symmetricDifference(Set1, Set2)要求传入 2,即使我使用 Sets.newHashSet(lis1) 和 Sets.newHashSet(lis2) 创建两个集合,但它们在集合中仍然具有不同类型的对象。

或者在公共CollectionUtils.disjunction(lis1, list2)列表中仍然必须包含相同的对象类型

不做 2 个昂贵的 for 循环,还有其他方法吗?

4

3 回答 3

1

使用番石榴,试试这个。它对我有用->

Multisets.difference(multiset1,multiset2);

如何将 ArrayList 转换为 Multiset。

 List x = new ArrayList();
 x.add(3);.....

 Multiset newX = HashMultiset.create();
 newX.addAll(x);
于 2014-09-10T11:59:07.090 回答
1

首先,您必须将列表转换为基于字符串的列表:

private static final class FromObject1ToName implements Function<Object1, String> {
    @Override
    public String apply(Object1 input) {
        return input.name;
    }
}

必须对 Object2 进行相同的转换

然后变换输入列表:

 Collection<String> transformed = Collections2.transform(list1, new FromObject1ToName());

//list1 是 Object1 上的一个 List

然后创建多重集:

 Multiset<String> multiset1 = HashMultiset.create();
    multiset1.addAll(transformed);

然后简单地做:

 Multisets.difference(multiset1, multiset2) // multiset1 is from Object1 and multiset2 is from Object2

这将为您提供差异以及差异的次数

如果您只需要知道差异,则执行相同的转换,然后将字符串集合加载到 Set 和然后执行 Sets.symmetricDifference

于 2014-09-10T14:08:52.773 回答
1

首先,我们将构建两个映射,每个列表一个映射,将名称映射到对象。然后我们遍历键集之间的差异,处理具有该名称的任何类型的对象。这些地图让我们避免扫描列表以寻找具有该名称的对象。(在使用 Map 而不是 Multimap 时,我依赖提问者对另一个答案的评论,即在每个列表中,名称都是唯一的。如果您仍在使用 Java 7,请将方法引用替换为 Function 实现。)

Map<String, Object1> map1 = Maps.uniqueIndex(list1, Object1::getName);
Map<String, Object2> map2 = Maps.uniqueIndex(list2, Object1::getName);
for (String name : Sets.difference(map1.keySet(), map2.keySet()))
    processObject1(map1.get(name));
for (String name : Sets.difference(map2.keySet(), map1.keySet()))
    processObject2(map2.get(name));

如果您只想在一个列表中构建列表或对象集,processObject1并且processObject2可以将对象添加到集合中。

uniqueIndex的迭代顺序是输入可迭代的,并difference返回具有与其第一个参数相同的迭代顺序的 SetView,因此如果该顺序与您的问题相关,您可以按照它们在输入列表中出现的顺序处理对象。


Java 8 流提供了基本相同的功能:

Map<String, Object1> map1 = list1.stream().collect(Collectors.toMap(Function.identity(), Object1::getName));
Map<String, Object2> map2 = list2.stream().collect(Collectors.toMap(Function.identity(), Object2::getName));
map1.keySet().stream().filter(n -> !map2.keySet().contains(n)).map(map1::get).forEachOrdered(o1 -> processObject1(o1));
map2.keySet().stream().filter(n -> !map1.keySet().contains(n)).map(map2::get).forEachOrdered(o2 -> processObject1(o2));

同样,如果您只想收集对象,可以将forEachOrdered调用替换为。collect(Collectors.toList())

于 2014-09-17T22:49:00.217 回答