我如何比较两个可能具有不同长度的数组并获得每个数组之间的差异?
例如:
Cat cat = new Cat();
Dog dog = new Dog();
Alligator alligator = new Alligator();
Animal animals[] = { cat, dog };
Animal animals2[] = { cat, dog, alligator };
我如何将它们与两个数组进行比较并使其返回Alligator
的实例?
答案 0 :(得分:5)
我建议您的问题需要澄清。目前,每个人都在猜测你实际要问的是什么。
new Cat()
“等于”new Cat()
吗?你的例子暗示它确实!! 假设这些数组是真正的集合,那么您可能应该使用HashSet
而不是数组,并使用addAll
和retainAll
等集合操作来计算设定差异。
另一方面,如果数组用于表示列表,那么“差异”意味着什么并不清楚。
如果代码运行速度很快,那么您肯定需要重新考虑数据结构。如果你总是从数组开始,你将无法快速计算“差异”...至少在一般情况下。
最后,如果你打算使用任何依赖于equals(Object)
方法的东西(包括任何Java集合类型,你真的需要清楚地理解“equals”应该是什么意思在你的应用程序中。所有Cat
实例是否相等?它们是否都不同?某些Cat
实例是否相等而其他实例是否相同?如果你没有想到这一点,那就实现equals
和因此,hashCode
方法会让您感到困惑。
答案 1 :(得分:1)
好吧,您可以改用Set
并使用removeAll()
方法。
或者您可以使用以下简单和慢速算法:
List<Animal> differences = new ArrayList<Animal>();
for (Animal a1 : animals) {
boolean isInSecondArray = false;
for (Animal a2 : animals2) {
if (a1 == a2) {
isInSecondArray = true;
break;
}
}
if (!isInSecondArray)
differences.add(a1)
}
然后differences
将包含animals
数组中但不在animals2
数组中的所有对象。以类似的方式,您可以执行相反的操作(获取animals2
但不在animals
中的所有对象。)
答案 2 :(得分:1)
我建议您将对象放入集合中,然后使用集合的交集:
// Considering you put your objects in setA and setB
Set<Object> intersection = new HashSet<Object>(setA);
intersection.retainAll(setB);
之后,你可以使用removeAll来改变两组中的任何一组:
setA.removeAll(intersection);
setB.removeAll(intersection);
灵感来自:http://hype-free.blogspot.com/2008/11/calculating-intersection-of-two-java.html
答案 3 :(得分:1)
您可能需要查看此文章以获取更多信息:
http://download-llnw.oracle.com/javase/tutorial/collections/interfaces/set.html
正如前面提到的那样,removeAll()
就是这样做的,但是你需要做两次,这样你就可以创建两者中所有缺失的列表,然后你可以将这两个结果组合起来列出所有差异。
但是,这是一种破坏性操作,因此如果您不想丢失信息,请复制Set
并对其进行操作。
<强>更新强>
看来我对数组中的内容的假设是错误的,所以removeAll()
不起作用,但是要求5ms,依赖于要搜索的项目数可能是个问题。
因此,HashMap<String, Animal>
似乎是最佳选择,因为搜索速度很快。
Animal是一个至少包含一个属性String name
的接口。对于为Animal
和Equals
实现hashCode
实现List<Object>
的每个类。你可以在这里找到一些讨论:http://www.ibm.com/developerworks/java/library/j-jtp05273.html。这样,如果您希望哈希值是动物类型和名称的组合,那么就可以了。
因此,基本算法是将所有内容保存在哈希映射中,然后搜索差异,只获取一组键,然后搜索以查看该键是否包含在另一个列表中,如果它不是把它放入{{1}},将值存储在那里。 你会想要这样做两次,所以,如果你至少有一个双核处理器,你可以从两个搜索在不同的线程中完成获得一些好处,但是你会想要使用添加的并发数据类型之一在JDK5中,您不必担心组合差异列表中的同步。
所以,我会先把它作为单线程和测试来编写,以获得一些关于速度有多快的想法,同时将它与原始的implmemntation进行比较。 然后,如果您需要更快,请尝试使用线程,再次比较以查看是否有速度增加。
在进行任何优化之前,请确保您已经掌握了已有的指标,以便比较并查看一次更改是否会提高速度。
如果您一次进行太多更改,可能会在速度方面有很大改进,但其他可能导致性能下降,而且不会看到,这就是为什么每次更改应该是一次一个
不要丢失其他实现,通过使用单元测试和测试每次100次,您可以了解每个更改给您带来的改进。
答案 4 :(得分:0)
我不关心我的用法性能(你也不应该,除非你有充分的理由,并且你通过你的分析器发现这个代码是瓶颈)。
我所做的与功能性答案类似。我使用LINQ set运算符来获取每个列表的异常:
http://msdn.microsoft.com/en-us/library/bb397894.aspx
修改强>
抱歉,我没注意到这是Java。对不起,我在C#la-la的土地上,他们看起来非常相似:)