我可以如何比较两个可能长度不同的数组,并得到每个数组之间的差异呢?
例如:
Cat cat = new Cat();
Dog dog = new Dog();
Alligator alligator = new Alligator();
Animal animals[] = { cat, dog };
Animal animals2[] = { cat, dog, alligator };
我该如何比较这两个数组并返回 Alligator
的实例?
我可以如何比较两个可能长度不同的数组,并得到每个数组之间的差异呢?
例如:
Cat cat = new Cat();
Dog dog = new Dog();
Alligator alligator = new Alligator();
Animal animals[] = { cat, dog };
Animal animals2[] = { cat, dog, alligator };
我该如何比较这两个数组并返回 Alligator
的实例?
new Cat()
是否与new Cat()
相等?您的示例表明它确实如此!
- “差异”是什么意思?您是否指集合差异?
- 如果两个数组长度相同,您希望发生什么?
- 这是一次性比较还是针对相同数组重复出现?
- 数组中有多少个元素(平均)?
- 您为什么要使用数组?HashSet
而不是数组,并使用集合操作(例如addAll
和retainAll
)来计算集合差异。equals(Object)
方法的内容(包括任何Java集合类型),则确实需要清楚地了解在您的应用程序中“equals”应该意味着什么。所有Cat
实例是否相等?他们都不同吗?一些Cat
实例相等,而其他实例则不相等吗?如果您没有弄清楚这一点,并相应地实现equals
和hashCode
方法,则会得到令人困惑的结果。你可以使用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
中的对象)。
// 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://download-llnw.oracle.com/javase/tutorial/collections/interfaces/set.html
如前所述,removeAll()
是为此而设计的,但您将需要执行两次此操作,以便您可以创建一个在两个集合中都不存在的所有元素列表,然后您可以将这两个结果组合在一起,以获得所有差异的列表。
但是,这是一项破坏性的操作,因此如果您不想丢失信息,请复制Set
并对其进行操作。
更新:
看起来我的数组内容假设是错误的,因此removeAll()
无法使用,但是在5毫秒的要求下,根据搜索项目的数量,可能会出现问题。
因此,似乎HashMap<String, Animal>
是最佳选择,因为它在搜索方面很快。
Animal是一个至少有一个属性String name
的接口。对于每个实现了Animal
的类,编写Equals
和hashCode
的代码。你可以在这里找到一些讨论:http://www.ibm.com/developerworks/java/library/j-jtp05273.html。这样,如果你希望哈希值是动物类型和名称的组合,那就没问题了。
所以,基本算法是将所有内容保存在哈希表中,然后搜索差异,只需获取键的数组,并搜索以查看该键是否包含在另一个列表中,如果没有,则将其放入List<Object>
中并存储该值。
您需要执行此操作两次,因此,如果您至少拥有双核处理器,则可以从将两个搜索分别在不同线程中完成中获得一些好处,但是您将需要使用JDK5中添加的并发数据类型之一,以便您无需担心在差异组合列表中的同步问题。
所以,我会先将其作为单线程编写并进行测试,以了解它有多快,同时与原始实现进行比较。
然后,如果你需要更快的速度,请尝试使用线程,再次进行比较,查看是否有速度提升。
在进行任何优化之前,确保您已经对您所拥有的一些指标有所了解,这样您就可以进行比较,看看一个改变是否会导致速度提升。
如果您一次性进行太多更改,其中一些可能会大幅提高速度,但其他更改可能会导致性能下降,并且不会被发现,这就是为什么每次只能进行一项更改的原因。
不要失去其他实现方式,通过使用单元测试和每个测试100次,您可以了解每个更改带来的改进。
我不关心我的用途的性能(除非你有充分的理由,并且通过分析器发现这段代码是瓶颈),你也不应该。
我的做法类似于functional的回答。我使用LINQ集合运算符来获取每个列表上的异常:
http://msdn.microsoft.com/en-us/library/bb397894.aspx
编辑:
抱歉,我没有注意到这是Java。对不起,我在C#的世界里迷失了,它们看起来非常相似 :)