我正在寻找在Java中执行此操作的优雅而有效的方法:
public class Object1{
String name;
int age;
}
public class Object2{
String name;
String adress;
}
List<Object1> list1;
List<Object2> list2;
如果list2中的Object2具有相同的名称,我想查找list1中的每个Object1。 有没有比我写下面更好的方法?
for (Object1 element1 : list1) {
for (Object2 element2 : list2) {
if (element2.name.equals(element1.name)){
// DO MY STUFF
}
}
}
答案 0 :(得分:1)
如果要对这些类中的名称实施比较器,可以对它们进行排序。 将这些列表排序后,将允许您对它们进行二进制搜索。 那么你想对Object1中的每个元素做什么,在object2中进行二进制搜索。
这将使您的代码更快,从O(n * m)复杂度到O(n * log(m))复杂度。
答案 1 :(得分:1)
对于两个大小为n和m的列表,您当前的算法的运行时间为O(n * m)。
您可以在O(nlog(n)+ mlog(m))时间内对列表进行预排序,然后在两个列表上迭代一次以查找具有相同名称的元素(迭代将采用O(m + n) )。
因此,如果n是较大列表的大小,则可以使用O(nlog(n))算法而不是当前的O(n ^ 2)。
迭代步骤看起来类似于合并排序的合并部分。
int i=0;
int j=0;
while (i<list1.size() && j<list2.size()) {
if (list1.get(i).getName().compareTo(list2.get(j).getName())<0) {
i++;
} else if (list1.get(i).getName().compareTo(list2.get(j).getName())>0) {
j++;
} else {
// list(i).getName() is equal to list(j).getName()
}
}
while (i < list1.size() && list1.get(i).getName().equals(list2.get(list2.size()-1).getName()) {
// list(i).getName() is equal to the name of the last element in list2
i++;
}
while (j < list2.size() && list2.get(j).getName().equals(list1.get(list1.size()-1).getName()) {
// list(j).getName() is equal to the name of the last element in list1
j++;
}
答案 2 :(得分:1)
我可能会使用地图:
Map<String, Object1> m = new HashMap<>();
for( Object1 o1 : list1 ) {
m.put(o1.name, o1);
}
for( Object2 o2 : list2 ) {
Object1 o1 = m.get(o2.name);
if( o1 != null ) {
//do something
}
}
如果允许多个具有相同名称的对象,您可以使用支持此对象的地图,例如
Multimap并自行维护列表。这应该降低O(n + m)的复杂度,O(n)用于构建映射,O(m)用于检查list2。构建地图有一些不断的开销,但根据这些列表的大小,可能会有相当大的加速。
更新:
我做了排序优先和地图方法的快速基准测试,虽然排序优先可能没有高度优化(我使用Map<String, List<Object1>>
然后同时迭代两个集合),地图方法似乎很快提高效率。
以下是我的机器的一些结果:
Collections.sort()
答案 3 :(得分:0)
在break
DO MY STUFF
for (Object1 element1 : list1)
{
for (Object2 element2 : list2)
{
if (element2.name.equals(element1.name))
{
// DO MY STUFF
break;
}
}
}