当前位置:  开发笔记 > 编程语言 > 正文

如何最好地比较Java中的两个集合并采取行动?

如何解决《如何最好地比较Java中的两个集合并采取行动?》经验,为你挑选了3个好方法。

我有两个相同对象的集合,Collection oldSetCollection newSet.所需的逻辑如下:

如果foo是(*)oldSet但不是newSet,请致电doRemove(foo)

否则,如果foo不在,oldSet但在newSet,呼叫doAdd(foo)

否则,如果foo在两个集合中但已修改,请调用doUpdate(oldFoo, newFoo)

否则,如果!foo.activated && foo.startDate >= now,打电话doStart(foo)

否则,如果foo.activated && foo.endDate <= now,打电话doEnd(foo)

(*)"in"表示唯一标识符匹配,不一定是内容.

目前的(传统)的代码做了很多比较,以计算出removeSet,addSet,updateSet,startSetendSet,然后循环,在每个项目采取行动.

代码非常混乱(部分是因为我已经遗漏了一些意大利面条逻辑)而我正在尝试重构它.更多背景信息:

据我所知,oldSetnewSet实际上是由支持ArrayList

每套包含少于100件物品,最多可能是20件

这个代码经常被调用(以百万/天为单位),尽管这些代码很少有所不同

我的问题:

如果我转换oldSetnewSetHashMap(顺序并不关心这里的),用ID作为键,这将使得代码更易于阅读和更容易比较?转换损失了多少时间和内存性能?

迭代这两组并执行适当的操作会更有效和简洁吗?

小智.. 34

Apache的commons.collections库有一个CollectionUtils类,它为Collection操作/检查提供了易于使用的方法,例如intersection,difference和union.

org.apache.commons.collections.CollectionUtils API文档在这里.



1> 小智..:

Apache的commons.collections库有一个CollectionUtils类,它为Collection操作/检查提供了易于使用的方法,例如intersection,difference和union.

org.apache.commons.collections.CollectionUtils API文档在这里.



2> Vitalii Fedo..:

例如,您可以使用Java 8流

set1.stream().filter(s -> set2.contains(s)).collect(Collectors.toSet());

或者 从Guava中设置类:

Set intersection = Sets.intersection(set1, set2);
Set difference = Sets.difference(set1, set2);
Set symmetricDifference = Sets.symmetricDifference(set1, set2);
Set union = Sets.union(set1, set2);



3> martinatime..:

我已经使用Java中的Collections Framework创建了我认为您正在寻找的近似值.坦率地说,我认为这可能是过度的,因为@Mike Deck指出.对于这样一小组要比较和处理的项目,我认为数组从程序角度来看是更好的选择,但这里是我的伪编码(因为我很懒)解决方案.我假设Foo类基于它的唯一id而不是它的内容中的所有数据是可比较的:

Collection oldSet = ...;
Collection newSet = ...;

private Collection difference(Collection a, Collection b) {
    Collection result = a.clone();
    result.removeAll(b)
    return result;
}

private Collection intersection(Collection a, Collection b) {
    Collection result = a.clone();
    result.retainAll(b)
    return result;
}

public doWork() {
    // if foo is in(*) oldSet but not newSet, call doRemove(foo)
    Collection removed = difference(oldSet, newSet);
    if (!removed.isEmpty()) {
        loop removed {
            Foo foo = removedIter.next();
            doRemove(foo);
        }
    }
    //else if foo is not in oldSet but in newSet, call doAdd(foo)
    Collection added = difference(newSet, oldSet);
    if (!added.isEmpty()) {
        loop added  {
            Foo foo = addedIter.next();
            doAdd(foo);
        }
    }

    // else if foo is in both collections but modified, call doUpdate(oldFoo, newFoo)
    Collection matched = intersection(oldSet, newSet);
    Comparator comp = new Comparator() {
        int compare(Object o1, Object o2) {
            Foo f1, f2;
            if (o1 instanceof Foo) f1 = (Foo)o1;
            if (o2 instanceof Foo) f2 = (Foo)o2;
            return f1.activated == f2.activated ? f1.startdate.compareTo(f2.startdate) == 0 ? ... : f1.startdate.compareTo(f2.startdate) : f1.activated ? 1 : 0;
        }

        boolean equals(Object o) {
             // equal to this Comparator..not used
        }
    }
    loop matched {
        Foo foo = matchedIter.next();
        Foo oldFoo = oldSet.get(foo);
        Foo newFoo = newSet.get(foo);
        if (comp.compareTo(oldFoo, newFoo ) != 0) {
            doUpdate(oldFoo, newFoo);
        } else {
            //else if !foo.activated && foo.startDate >= now, call doStart(foo)
            if (!foo.activated && foo.startDate >= now) doStart(foo);

            // else if foo.activated && foo.endDate <= now, call doEnd(foo)
            if (foo.activated && foo.endDate <= now) doEnd(foo);
        }
    }
}

至于你的问题:如果我将oldSet和newSet转换为HashMap(此处不关注顺序),将ID作为键,是否会使代码更容易阅读并更容易比较?转换损失了多少时间和内存性能?我认为你可能会通过使用Map BUT使代码更具可读性...你可能会在转换过程中使用更多的内存和时间.

迭代这两组并执行适当的操作会更有效和简洁吗?是的,这将是两全其美的,特别是如果您遵循@Mike Sharek的建议,使用专门的方法滚动您自己的列表,或者按照访客设计模式来运行您的收集和处理每个项目.

推荐阅读
手机用户2402852387
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有