【问题标题】:Merge two collections (with duplication) to one collection (without duplication)将两个集合(有重复项)合并为一个集合(没有重复项)
【发布时间】:2017-01-05 00:50:42
【问题描述】:

我在多个客户端上同步数据时遇到问题。 为简单起见,假设我有两个可能重复的集合(name 是关键):

"collection1": [
    {
    "name": "a",
    "timestamp": 1
  },
    {
    "name": "a",
    "timestamp": 2
  },
    {
    "name": "b",
    "timestamp": 1
  }]

   "collection2": [
    {
    "name": "a",
    "timestamp": 3
  },
    {
    "name": "c",
    "timestamp": 2
  }]

我希望收集没有重复(name 是关键),具有最高的时间戳值。所以合并后应该是这样的:

"collection3": [
     {
    "name": "b",
    "timestamp": 1
  },
    {
    "name": "a",
    "timestamp": 3
  },
    {
    "name": "c",
    "timestamp": 2
  }]

顺便说一句。我不在乎秩序。 我不能简单地 Set = new HashSet(collectionn); 因为缺少替换重载。

我的想法是做 3 次 removeDuplication

  1. collection1 和 collection1
  2. collection2 和 collection2
  3. collection1 与 collection2

使用这个 O(n^2) removeDuplication 函数:

LinkedList<MyObject> finalList = new LinkedList<>();

    for (MyObject newObject : collection) {
        boolean foundSimillar = false;
        for (MyObject objectAlreadyAdded : finalList) {
            if (Objects.equals(newObject, objectAlreadyAdded)) { // in this case if(name1 == name2)
                foundSimillar = true;
                long newObjectTime = newObject.lastTimeModified;
                long alreadyAddedObjectTime = objectAlreadyAdded.lastTimeModified;
                if (newObjectTime > alreadyAddedObjectTime) {
                    finalList.remove(objectAlreadyAdded);
                    finalList.add(newObject);
                    break;
                }
            }
        }
        if(!foundSimillar)
            finalList.add(newObject);
    }

还有比我的 3 * O(n^2) 更有效的算法吗?

【问题讨论】:

  • 是否有不能创建空哈希集的原因。然后,对于列表中的每个项目,检查它是否在哈希集中,如果没有则添加它?那将是 O(n)。
  • @JimMischel 如果已经有项目,但时间戳较低怎么办?它需要更换,但不能。
  • 当然可以。从哈希集中删除现有的并添加新的。或者,使用地图并更新它。

标签: java algorithm collections merge


【解决方案1】:

您应该可以使用地图来执行此操作。您只需检查键是否在地图中(如果 newValue > oldValue 则更新值),否则移动到下一个元素。

总时间复杂度应该是O(N)

所有插入完成后,您可以通过一次迭代重建您的 json。

【讨论】:

    【解决方案2】:

    您可以在 O(N) 时间内使用标准流收集器完成此操作:

    Collection<Thing> merged =
            Stream.of(collection1, collection2)
            .flatMap(Collection::stream)
            .collect(groupingBy(Thing::getName, Collectors.maxBy(Comparator.comparing(Thing::getTimestamp))))
            .values()
            .stream()
            .map(Optional::get)
            .collect(Collectors.toList());
    

    【讨论】:

    • Android 还不完全支持 Java 8 :/
    【解决方案3】:

    如果您使用的是 Java 8 并将值存储在地图中,那么如果您可以更新当前集合而不是创建新集合,那么您可以一步完成整个操作:

    Map<String, Date> map1, map2;
    
    map1.forEach((n, d) -> map2.merge(n, d, (d1, d2) -> d1.after(d2) ? d1 : d2));
    

    Map.merge 是一个非常聪明的方法。如果它不存在,它会添加键和值。如果是,那么它将应用给定的函数来确定要使用的值。非常适合您的情况。

    如果您希望它在新地图中而不是旧地图中:

    Map<String, Date> map3 = new HashMap<>(map1);
    map2.forEach((n, d) -> map3.merge(n, d, (v1, v2) -> v1.after(v2) ? v1 : v2));
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-10-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多