Java 8:按键合并两个包含对象的列表

2022-09-04 23:11:26

我有两个列表:

List<Server> servers1 = new ArrayList<>();
Server s1 = new Server("MyServer");
s1.setAttribute1("Attribute1");
servers1.add(s1);

List<Server> servers2 = new ArrayList<>();
Server s2 = new Server("MyServer");
s2.setAttribute2("Attribute2");
servers2.add(s2);

servers1包含带有 a 和 an(但没有 )的服务器。
包含带有 a 和 an(但没有 )的服务器。nameattribute1attribute2servers2nameattribute2attribute1

public class Server {
   private String name;
   private String attribute1;
   private String attribute2;

   public Server(String name) { 
       this.name = name;
       this.attribute1 = "";
       this.attribute2 = "";
   }

   //Getters & Setters

}

有谁知道如何将这两个列表合并为一个列表,每个列表仅包含一次(by)但同时具有两个属性?Servername

有些服务器仅存在于一个或另一个列表中。最终列表应包含所有服务器。

    List<Server> servers1 = new ArrayList<>();
    Server s1 = new Server("MyServer");
    s1.setAttribute1("Attribute1");

    Server s2 = new Server("MyServer2");
    s2.setAttribute1("Attribute1.2");

    servers1.add(s1);
    servers1.add(s2);

    List<Server> servers2 = new ArrayList<>();
    Server s3 = new Server("MyServer");
    s3.setAttribute2("Attribute2");

    Server s4 = new Server("MyServer3");
    s4.setAttribute2("Attribute2.2");

    servers2.add(s3);
    servers2.add(s4);

应导致:

[服务器 [名称 = MyServer,属性 1 = 属性 1,属性 2 = 属性 2],

服务器 [名称 = MyServer2, 属性 1 = 属性 1.2, 属性 2 = ]]

服务器 [名称 = MyServer3, 属性 1=, 属性 2=属性 2.2]]

//解决方案(感谢大家的帮助!

Map<String, Server> serverMap1 = Stream.concat(servers1.stream(), servers2.stream())
            .collect(Collectors.toMap(Server::getName, Function.identity(), 
            (server1, server2) -> {
                server1.setAttribute2(server2.getAttribute2()); 
                return server1; 
            }));

答案 1

将每个列表转换为映射并合并它(我使用龙目岛不编写样板代码):

@Data
@NoArgsConstructor
@AllArgsConstructor
class Server {
    private String name;
    private String attribute1;
    private String attribute2;
}

public class ServerMain {

    public static void main(String[] args) {

        List<Server> servers1 = Arrays.asList(
                new Server("name1", "attr1.1", null),
                new Server("name2", "attr1.2", null));

        List<Server> servers2 = Arrays.asList(
                new Server("name1", null, "attr2.1"),
                new Server("name2", null, "attr2.2"));

        Map<String, Server> serverMap1 = servers1.stream().collect(Collectors.toMap(Server::getName, Function.identity()));
        Map<String, Server> serverMap2 = servers2.stream().collect(Collectors.toMap(Server::getName, Function.identity()));

        serverMap1.keySet().forEach(key -> serverMap1.merge(key,
                serverMap2.get(key),
                (server1, server2) -> {
                    server1.setAttribute2(server2.getAttribute2());
                    return server1;
                }));


        System.out.println(serverMap1);
    }
}

答案 2

对于 servers1 中的每个服务器,在 servers2 中找到一个匹配的 server2,并将第一个服务器缺少的属性设置为更正属性,否则如果没有匹配的服务器,则只需返回 null。另请注意,此实现将仅返回 servers1 中包含的服务器名称列表。

@AllArgsConstructor
@Data
private class Server {
   private String name;
   private String attribute1;
   private String attribute2;
}

List<Server> completServersInfo = servers1.stream()
     .map((server1 -> {
        Server matchingServer = servers2.stream()
           .filter(server2 -> server2.name.equals(server1.name))
           .findFirst()
           .orElse(null);
        server1.setAttribute2(matchingServer.attribute2);
        return server1;
     }))
     .collect(Collectors.toList());