Reputation: 679
I have two lists:
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
contains servers with a name
and an attribute1
(but no attribute2
).
servers2
contains servers with a name
and an attribute2
(but no attribute1
).
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
}
Does anyone know how I can merge these two lists to one list containing
each Server
only once (by name
) but with both attributes?
There are servers which only exist in one or the other list. The final list should contain all servers.
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);
should result in:
[Server [name=MyServer, attribute1=Attribute1, attribute2=Attribute2],
Server [name=MyServer2, attribute1=Attribute1.2, attribute2=]]
Server [name=MyServer3, attribute1=, attribute2=Attribute2.2]]
//SOLUTION (thx everybody for the help!)
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;
}));
Upvotes: 16
Views: 26332
Reputation: 5552
Maybe you can use a map to do it? The key of the map would be the name of the server and the value of the map is the object Server
.
Map<String, Server> map = new HashMap<>();
for (Server s : servers1) {
map.put(s.getName(), s);
}
for (Server s : servers2) {
String key = s.getName();
if (map.containsKey(key)) {
map.get(key).setAttribute2(s.getAttribute2());
} else {
map.put(key, s);
}
}
List<Server> servers = new ArrayList<>(map.values()); // or other impl.
Upvotes: 2
Reputation: 21
For each server in servers1 find a matching server2 in servers2 and set the missing attribute of the first one to correct attribute else if there is no matching server by name simply return null. Also note that this implementation will return only the list of servers name contained in 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());
Upvotes: 2
Reputation: 2286
Convert each list to map and merge it (I use Lombok to not write boilerplate code):
@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);
}
}
Upvotes: 4