将两个集合(带有重复项)合并到一个集合中(不重复)

时间:2017-01-05 00:50:42

标签: java algorithm collections merge

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

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

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

我希望收集没有重复(名称是关键),具有最高的时间戳值。所以在合并之后它应该看起来像:

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

顺便说一下。我不关心订单。 我不能简单地说 Set = new HashSet<>(collectionn); 因为没有替换过载。

我的想法是做3次removeDuplication

  1. collection1 with collection1
  2. collection2 with collection2
  3. collection1 with collection2
  4. 使用此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)更有效的算法?

3 个答案:

答案 0 :(得分:4)

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

总时间复杂度应为O(N)

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

答案 1 :(得分: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());

答案 2 :(得分:1)

如果您使用的是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));