【问题标题】:Outer Joining two List to generate a new List in Java外部加入两个列表以在 Java 中生成一个新列表
【发布时间】:2018-04-19 06:40:59
【问题描述】:

我正在尝试找到一种方法来连接具有两个唯一属性的两个对象列表以生成一个新的对象列表。

用户类

public class Users {

    String id;

    String name;

    String gender;

}

在这里添加一些数据

List<Users> userList=new ArrayList<Users>();
userList.add(new Users("1","AA","Male"));
userList.add(new Users("2","BB","Male"));
userList.add(new Users("3","CC","Female"));

学术班

public class Academics {

    String id;

    String name;

    String grade;

    String professional;

}

在这里添加一些数据

List<Academics> academicsList=new ArrayList<Academics>();
academicsList.add(new Academics("1","AA","A","Doctor"));
academicsList.add(new Academics("2","BB","B","Carpenter"));
academicsList.add(new Academics("3","CC","C","Engineer"));

我的个人资料

Public class Profile {

String id;

String name;

String gender;

String grade;

String professional;

}

这里我需要通过 Outer 加入 UserList 和 AcademicsList 来计算 List,其中有两个共同属性 idname

我确实需要将其作为批量操作执行,而不是一个接一个地使用任何 For/While 循环。

有什么方法可以使用Stream 来实现这一点吗?

更新 1: 这里的加入就像外加入一样,其中一些 id 不会出现在学术中,但会出现在用户中。 在这种情况下,我们需要在 Profile List(s) 中显示等级/专业的空值

提前致谢,
周杰伦

【问题讨论】:

  • 加入两个不同类型的列表是什么意思?结果列表的类型是什么?还是您的意思是“找到所有同时也是学者的用户”?
  • @sprinter 他想组合 UserList 和 AcademicsList 以形成我的个人资料的结果列表。
  • @saif ahmad :问题错过了细节。你想要什么类型的加入?如果您想要内部,则仅当您在两个输入列表中找到相同的 id 时才会填充结果列表。但是,如果您想要外连接,如果仅在两个输入列表之一中找到一个 id,您的列表也将被填充。这改变了要使用的算法的一切。所以短跑运动员的问题是合适的。
  • @saifahmad 我还是不明白。 Profile 有几个其他类中不存在的字段。对于新创建的对象,这些字段的值是多少?
  • @amanin :对不起,我错过了。我更新了问题。我需要在这里执行 OuterJoin

标签: java list arraylist java-stream


【解决方案1】:

将一个输入列表转换为地图是有意义的,以便在第一个和第二个列表的条目之间快速关联。

Map<String,Users> userByID = userList.stream().collect(Collectors.toMap(Users::getID,Function.identity));

现在您可以流式传输第二个列表的元素:

List<Profile> profiles = 
    academicsList.stream()
                 .map(a -> {
                     Profile p = null;
                     Users u = userByID.get(a.getID());
                     if (u != null) {
                         p = new Profile();
                         // now set all the Profile fields based on the properties
                         // of the Users instance (u) and the Academics instance (a)
                     }
                     return p;
                 })
                 .filter(Objects::nonNull)
                 .collect(Collectors.toList());

鉴于您的额外要求,您应该为第二个List 和第一个List 创建一个MapStream

Map<String,Academics> academicsByID = userList.stream().collect(Collectors.toMap(Academics::getID,Function.identity));

List<Profile> profiles = 
    userList.stream()
                 .map(u -> {
                     Profile p = new Profile ();
                     Academics a = academicsByID.get(u.getID());
                     // now set all the Profile fields based on the properties
                     // of the Users instance (u) and the Academics instance (a)
                     // (if available)
                     return p;
                 })
                 .collect(Collectors.toList());

【讨论】:

  • 您的回答很好,但我错过了我的问题中有关加入类型的信息。默认情况下,这对内部连接很有用。但我需要执行 Outer Join,其中profile 需要为academics 中的缺失属性显示空值。 P.S Users类的真相来源
  • @Jayendran 您可以做一个简单的更改 - 从第二个列表 (academicsList) 创建一个 Map 并流过第一个列表 (userList)。在 Stream 管道中,即使在 Map 中找不到 Academics 实例,也要创建 Profile。
  • 你成功了。 !它完美地工作。只有一个问题。您单独使用Id 作为身份。但实际数据具有结合idname的唯一性。有没有办法将name 包含为业务密钥。
  • @Jayendran 您可以连接 ID 和名称并将其用作 Map 的键。而不是Users::getID,写u-&gt;u.getID()+u.getName()。然后把academicsByID.get(u.getID())改成academicsByID.get(u.getID()+u.getName());
猜你喜欢
  • 2017-12-09
  • 1970-01-01
  • 2012-03-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-12-24
  • 2018-05-07
相关资源
最近更新 更多