如何高效地基于关键字比较对象数组列表?

3
如何高效地基于关键字比较对象的ArrayList。
我有一个包含personDetails和departmentDetails对象的数组。
在这里,我试图找出两个对象之间基于属性deptCode的差异。
以下是我的尝试。
package com.education;

import java.util.*;
import java.util.stream.Collectors;

public class educationMain {

    public static void main(String[] args) {
        
        List<person> list=new ArrayList<person>();  
        person l1 = new person(1,"Samual",100,"Sales","Business");
        person l2 = new person(2,"Alex",100,"Sales","Business");
        person l3 = new person(3,"Bob",101,"Engineering","Technology");
        person l4 = new person(4,"Michel",101,"Engineering","Technology");
        person l5 = new person(5,"Ryan",102,"PR","Services");
        person l6 = new person(6,"Horward",103,"Leadership","Managmnet");
        person l7 = new person(7,"Cyna",104,"HR","Human Resource");
        list.add(l1);  
        list.add(l2);  
        list.add(l3); 
        list.add(l4);  
        list.add(l5);  
        list.add(l6); 
        list.add(l7); 
        
        
        
         List<department> depList = new ArrayList<department>();
         
         
         department d1 = new department(100, "Sales","Business");
         department d2 = new department(101, "Engineering","Technology");
         department d3 = new department(102, "PR","Services");
         depList.add(d1);  
         depList.add(d2);  
         depList.add(d3); 

         List<person> listC = new ArrayList<person>();
         
         
         for(person p : list) {
             boolean  flag = false;
             for (department d:depList) {
                 if(p.deptCode == d.deptCode) {
                     flag = false;
                     break;
                 }else {
                     flag = true;
                 }
             }
             if(flag == true) {
                 listC.add(p);
             }
         }
         
         for(person b:listC){  
             System.out.println(b.personId+" "+b.name+" "+b.deptCode+" "+b.parentDept+" "+b.deptName); 
         }
    }

}

现在我能打印出我想要的内容。但是我使用了两个for循环。有没有人可以帮助我优化我的代码,因为我在这里使用了两个循环。我想尝试根据某些条件过滤掉delta的代码。

在Collection中我看到set会做到这一点,但是我无法写出来。有没有人可以帮助我优化效率。

输出:

6 Horward 103 Leadership Managmnet

 7 Cyna 104 HR Human Resource

1
你正在寻找list中的person对象,其deptCode与所有departmentdeptCode都不匹配?这是算法的意图吗? - jason44107
1
@jason44107,完全一样。我已经在我的问题中更新了输出。如果有更高效的方法会很有帮助。 - David
2个回答

1

给定一个人员列表大小为p和一个部门列表大小为d,您当前的算法复杂度为O(p * d)

您可以遍历部门一次,将它们的部门代码添加到HashSet<Integer>中,并检查每个人的部门代码是否在该集合中 - 复杂度:O(d + p)。 这样计算上更有效率,但需要更多的内存 - 典型的时间与内存之间的权衡:

List<Person> persons = ...;
List<Department> departments = ...

Set<Integer> existingDepartmentIds = new HashSet<>();
for (Department d : departments) {
    existingDepartmentIds.add(d.deptCode); 
}

List<Person> personsWithMatchingDepartmentId = new ArrayList<>();
for (Person p : persons) {
   if (existingDepartmentIds.contains(p.deptCode)) {
       personsWithMatchingDepartmentId.add(p);
   }
}

我以命令式风格编写了这个代码,因为我不知道你是否熟练掌握 Stream 等技术。函数式版本的代码如下:

List<Person> persons = ...;
List<Department> departments = ...

Set<Integer> existingDepartmentIds = departments.stream()
   .map(Department::getDeptCode)
   .collect(Collectors.toSet());


List<Person> personsWithMatchingDepartmentId = persons.stream()
    .filter(p -> existingDepartmentIds.contains(p.deptCode))
    .collect(Collectors.toList());

我正在尝试,你能推荐任何可行的示例吗? - David

1

roookeee已经给出了很好的答案。我的方法与他差不多,这是我的实现:

在将所有部门添加到列表后,遍历各个部门,将代码添加到HashSet中。我不确定类方法具体是什么,但假设它们遵循JavaBean约定,代码可能如下所示:

//Create an instance of HashSet
HashSet<Integer> codeSet = new HashSet<>();

//Iterate over the departments and add the department code to a set.
depList.forEach(dept->{
    codeSet.add(dept.getDeptCode());
  });


List<person> listC = new ArrayList<>();

list.forEach(p->{
    if(!codeSet.contains(p.getDeptCode())){
    listC.add(p);
    }
  });

/**
 *This reads logically as, "For each person, if the set of department codes 
 *DOES NOT contain this persons department code, add them to the list".
 */


请原谅任何糟糕的代码格式,我已经有一段时间没有使用Java了,因为我一直在尝试学习Python。此外,我没有专业的编程经验,我只是一个认为编码很酷的少年,所以不要把我的话当作真理。

出于好奇,一个快速的问题..这是发生在对象的一个属性上。我们是否可以为多个属性执行相同的逻辑? - David
当然,如果您想检查多个条件,只需在if语句中添加“and”或“or”。例如,if(x && y){\\do something} 表示“如果x和y都为真,则执行某些操作”。 if(x || y){\\do something} 表示“如果x或y中的任意一个或两个都为真,则执行某些操作。” - confusedkingbread
我已经在这里单独提问了。https://stackoverflow.com/questions/68766785/how-to-takeout-attribute-from-two-arralylist-of-object-which-have-different-matc - David
就如何高效地做到这一点,我不太确定,我需要花些时间思考。我还没有学习足够的时间复杂度知识,以至于这些事情不能自然而然地出现在我的脑海中。我会去查看并可能稍后回答。 - confusedkingbread
实际上我想避免在这里使用两个循环。就是这样。我也在寻找一些基于关键字的解决方案。谢谢。 - David
1
你想根据列表b的数据检查列表a的每个元素 - 这是不可能的,没有两个循环。算法可以更改为不使用嵌套循环(就像解释的那样),但我们无法摆脱这两个循环。 - roookeee

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接