2017-01-12 2 views
5

У меня есть два списка:Java 8: Объединение двух списков, содержащих объекты по ключевым

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 содержит серверы с name и attribute1 (но не attribute2).
servers2 содержит серверы с name и attribute2 (но не 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 

} 

Кто-нибудь знает, как я могу объединить эти два списка один список, содержащий каждый Server только один раз (по name), но с обоими атрибутами?

Есть серверы, которые существуют только в одном или другом списке. Окончательный список должен содержать все серверы.

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, attribute1 = attribute1, attribute2 = attribute2],

сервера [имя = MyServer2, attribute1 = Attribute1.2, attribute2 =] ]

сервера [имя = MyServer3, attribute1 =, attribute2 = Attribute2.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; 
      })); 
+0

Создайте карту 'name' на' Server' с 'servers1', а затем заполните отсутствующий' attribute2' с 'servers2', ища сервер на карте по имени. Попытайтесь написать код самостоятельно. – lexicore

+0

Если это весь ваш класс 'Server', то как сущности в' List' имеют значения для 'name',' attribute1' или 'attribute2'. Если это не весь класс, укажите конструктор (ы) – CraigR8806

+0

Имеются ли в двух списках всегда одни и те же серверы или существуют серверы, которые не будут объединены? –

ответ

2

Преобразовать каждый список для отображения и объединить его (я использую Ломбок, чтобы не написать шаблонный код):

@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); 
    } 
} 
+0

Ничего, теперь я вижу, что это то, что делает Ломбок – CraigR8806

+1

Вы делаете слишком много работы, собирая на две карты, чтобы выполнять два поиска карт для каждого сервера. Вы можете полностью удалить «serverMap2» и просто «server2.forEach (s -> serverMap1.merge (s.getName(), s,/* те же функции слияния, что и раньше * /)); ' – Holger

+4

Если вы уверены, что ключи уникальны, вы можете сделать это даже в одной операции Stream:' serverMap1 = Stream.concat (servers1 .stream(), servers2.stream()) .collect (Collectors.toMap (Server :: getName, Function.identity(),/* те же функции слияния, что и раньше * /)); ' – Holger

0

Для каждого сервера в servers1 найти соответствующий server2 в servers2 и установите отсутствующий атрибут первого, чтобы исправить атрибут else, если нет соответствующего сервера по имени, просто верните null. Также обратите внимание, что эта реализация вернет только список имен серверов, содержащихся в серверах1.

@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()); 
+0

, если вы уверены, что один и тот же ключ существует в обоих списках Карта serverMap1 = servers1.stream(). Collect (Collectors.toMap (Server :: getName, Function.identity())); servers2 .forEach (ключ-> серверMap1.get (ключ.getName()). SetAttribute2 (key.getAttribute2())); System.out.println (serverMap1); –

+0

тот же ключ не должен существовать в обоих списках. Если это не так, сервер должен появиться в конечном списке как есть (с отсутствующими аргументами) – Nibor

0

Возможно, вы можете использовать карту для того, чтобы сделать это? Ключом карты будет имя сервера, а значением карты будет объект 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. 
Смежные вопросы