【问题标题】:How can I compare two MultiMaps?如何比较两个 MultiMap?
【发布时间】:2015-11-22 03:27:38
【问题描述】:

我有两个多图,它们是从两个巨大的 CSV 文件创建的。

Multimap<String, SomeClassObject> mapOne = ArrayListMultimap.create();
Multimap<String, SomeClassObject> mapTwo = ArrayListMultimap.create();

我假设一个 CSV 列作为一个键,每个键都有数千个与之关联的值。这些Multimaps 中包含的数据应该相同。现在我想比较这些Multimaps 中的数据,看看是否有不同的值。以下是我正在考虑的两种方法:

方法一:

Multimap 中列出一份大清单。这个大列表将包含一些单独的列表。每个较小的列表都包含一个唯一值,它是从 Multimap 读取的“键”及其关联值,这些值将构成该单独列表的其余部分。

ArrayList<Collection<SomeClassObject>> bigList = new ArrayList<Collection<SomeClassObject>>();

bigList 内将是单独的小列表 A、B、C 等。

我计划在检查第二个 Multimap 中的单个列表包含该“关键”元素的基础上,从两个文件的每个 bigList 中选择单个列表。如果是,则比较这两个列表并找出无法匹配的内容。

方法二:

比较两个Multimaps,但我不知道该怎么做。

哪种方法的执行时间应该更短?我需要在最短的时间内完成操作。

【问题讨论】:

  • 您想知道“是否”它们相等,还是想获取缺失值的列表?
  • “我有两个多图,它们是从两个巨大的 CSV 文件创建的。”那你为什么要在内存中做呢?为什么不使用数据库?
  • @durron597 首先检查在第一个多图中检查的条目键是否在第二个多图中可用。如果是,则检查两个多图中与该键关联的值在各个方面都相等。如果它们在任何方面存在差异,则该记录将被视为不同,需要取出并进行相应处理。

标签: java csv arraylist guava multimap


【解决方案1】:

使用Multimaps.filterEntries(Multimap, Predicate)

如果你想得到两个Multimaps之间的差异,很容易写一个基于containsEntry的过滤器,然后使用过滤行为来高效地找出所有不匹配的元素。只需基于一张地图构建Predicate,然后过滤另一张地图。

这就是我的意思。在这里,我使用的是 Java 8 lambda,但您可以查看这篇文章的修订历史以查看 Java 7 版本:

public static void main(String[] args) {
  Multimap<String, String> first = ArrayListMultimap.create();
  Multimap<String, String> second = ArrayListMultimap.create();
  
  first.put("foo", "foo");
  first.put("foo", "bar");
  first.put("foo", "baz");
  first.put("bar", "foo");
  first.put("baz", "bar");
  
  second.put("foo", "foo");
  second.put("foo", "bar");
  second.put("baz", "baz");
  second.put("bar", "foo");
  second.put("baz", "bar");
       
  Multimap<String, String> firstSecondDifference =
      Multimaps.filterEntries(first, e -> !second.containsEntry(e.getKey(), e.getValue()));
  
  Multimap<String, String> secondFirstDifference =
      Multimaps.filterEntries(second, e -> !first.containsEntry(e.getKey(), e.getValue()));
  
  System.out.println(firstSecondDifference);
  System.out.println(secondFirstDifference);
}

输出是不在另一个列表中的元素,在这个人为的例子中:

{foo=[baz]}
{baz=[baz]}

如果地图匹配,这些多地图将为空。


在 Java 7 中,您可以手动创建谓词,使用如下方式:

public static class FilterPredicate<K, V> implements Predicate<Map.Entry<K, V>> {
  private final Multimap<K, V> filterAgainst;

  public FilterPredicate(Multimap<K, V> filterAgainst) {
    this.filterAgainst = filterAgainst;
  }

  @Override
  public boolean apply(Entry<K, V> arg0) {
    return !filterAgainst.containsEntry(arg0.getKey(), arg0.getValue());
  }
}

将其用作Multimaps.filterEntries() 的参数,如下所示:

Multimap<String, String> firstSecondDifference =
    Multimaps.filterEntries(first, new FilterPredicate(second));

Multimap<String, String> secondFirstDifference =
    Multimaps.filterEntries(second, new FilterPredicate(first));

否则,代码与上面的Java 8版本相同(结果相同)。

【讨论】:

  • @user3044240 很高兴我能提供帮助,我很好奇,您在修订历史中使用的是 Java 8 lambda 版本还是 Java 7 版本?如果是 Java 7 版本,我会将其从修订历史中删除,以供未来用户使用。
  • Java 7 版本。我认为您应该将删除的代码放回原处。这更容易理解。谢谢。
  • @user3044240 它被重新编辑,以解释两个版本的方式。 Java 8 版本的代码要少得多,我将保留这两个版本,因为我们已经过了 Java 7 的正式生命周期结束,
  • 这听起来可能很烦人,但我只是将代码更改为使用 lambda 版本,但两种方式都运行良好。再次感谢!
  • @user3044240 也许未来的用户会找到这个答案并需要 Java 7 版本,我将保持原样。
【解决方案2】:

来自ArrayListMultimap.equals 文档:

比较指定的对象和这个多重映射是否相等。

如果对于每个键,两个 ListMultimap 实例包含相同顺序的相同值,则它们是相等的。如果值顺序不一致,则多图将不被视为相等。

所以只需mapOne.equals(mapTwo)。尝试自己做不会有更好的执行时间。

【讨论】:

  • 如何保证multimap的每个key的值顺序一致?
  • @durron597 我不知道,但 Jean 的回答表明,为了使用他的 equals 方法,需要顺序。我关心的是检查一个键的任何值是否在一个映射中被检查,它也应该在另一个映射的相同键的值中。如果找不到,则表示两个文件中的记录不同,需要处理。
  • @user3044240 它确实会检查订单,正如文档所述。与arrayList.equals(otherList) 相同。
  • @user3044240 再次阅读文档:“如果对于每个键,它们以相同的顺序包含相同的值,则两个 ListMultimap 实例是相等的。
  • @user3044240 为什么不SetMultimap? “如果对于每个键,两个 SetMultimap 实例包含相同的值,则它们是相等的。相等性不依赖于键或值的顺序。”
猜你喜欢
  • 2011-09-16
  • 2016-02-02
  • 2021-09-21
  • 2012-01-25
  • 2020-03-19
  • 2014-10-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多