Java 8 Stream, как объединить 2 списка не одинакового размера с пользовательской логикой для выбора дубликатов - PullRequest
0 голосов
/ 19 ноября 2018

У меня есть 2 списка объектов карты.

 "list1": [
    {
      "partyId": "1",
      "accountId": "1",
      "sourceSystem": "1",
    },
    {
      "partyId": "2",
      "accountId": "2",
      "sourceSystem": "2",
    }]

и это список 2.

 "list2": [
    {
      "partyId": "3",
      "accountId": "3",
      "sourceSystem": "3",
    },
    {
      "partyId": "1",
      "accountId": "2",
      "sourceSystem": "2",
    }]

Теперь мне нужно объединить list1 и list2, чтобы получить этот вывод.

 "merged": [
    {
      "partyId": "1",
      "accountId": "1",
      "sourceSystem": "1",
    },
    {
      "partyId": "2",
      "accountId": "2",
      "sourceSystem": "2",
    },
    {
      "partyId": "3",
      "accountId": "3",
      "sourceSystem": "3",
    }]

, так что вы можете видеть, что это объединяет 1,2 и 3 из списка1 и списка2. Кроме того, поскольку list2 имеет один partyId = 1 (также в list1), но детали (accountId и sourceSystem) отличаются, поэтому выбран partyId = 1 в list1.

Как я могу сделать это с потоком Java 8? Или единственный способ - преобразовать их в объекты Java и выполнить цикл for.

Ответы [ 3 ]

0 голосов
/ 19 ноября 2018

Вы можете сделать это так за один раз,

List<Map<String, String>> resultMap = Stream.concat(mapListOne.stream(), mapListTwo.stream())
    .collect(Collectors.groupingBy(m -> m.get("partyId"), Collectors.toList()))
    .entrySet().stream()
    .map(e -> e.getValue().get(0))
    .collect(Collectors.toList());

Это двухэтапное вычисление, при котором вы сначала вычисляете List карт для каждого значения partyId как карту, а затем получаете первый элемент в каждом List для вычисления окончательного результата.

0 голосов
/ 19 ноября 2018

если логика - это просто все элементы в первом списке плюс все элементы во втором списке, которые не соответствуют элементу в первом списке, тогда:

List<Map<String,String>> result = Stream.concat(list1.stream(),
    list2.stream().filter(m2 -> list1.stream()
        .noneMatch(m1 -> m1.get("partyId").equals(m2.get("partyId"))))
    .collect(Collectors.toList());
0 голосов
/ 19 ноября 2018

Одним из способов может быть итерация по первому списку и сбор в виде карты с использованием partyId в качестве key и Party в качестве value:

Map<String, CustomObject> customObjectMap = customObjectList1.stream()
        .collect(Collectors.toMap(CustomObject::getPartyId, customObject -> customObject, (a, b) -> b));

с последующей итерацией повторой список и фильтрация наших существующих идентификаторов partyIds

customObjectList2.stream()
        .filter(customObject -> !customObjectMap.containsKey(customObject.getPartyId()))
        .forEach(customObject -> customObjectMap.put(customObject.getPartyId(), customObject));

извлечение values из карты в качестве окончательного результата

List<CustomObject> merged = new ArrayList<>(customObjectMap.values());

Если изменение существующих коллекций не вредит вашемув любом случае, вы можете попытаться получить Set ключей на partyId из списка1

Set<String> partyIds = customObjectList1.stream().map(CustomObject::getPartyId).collect(Collectors.toSet());  // set assuming a list wouldn't have duplicate partyId

, а затем удалить объекты из другого списка на основе существующих ключей

customObjectList2.removeIf(p -> partyIds.contains(p.getPartyId()));

и, наконец, добавить все в один список объектов

customObjectList1.addAll(customObjectList2); // customObjectList1 is now your 'merged'
...