Как сгруппировать список списков, используя определенные критерии в Java 8 - PullRequest
0 голосов
/ 12 ноября 2018

У меня есть структура данных, как показано ниже.Я пытаюсь сгруппировать объекты таким образом, как Map<String, List<String>>, где ключ - это entryId, а значение - это список групп, к которым он принадлежит.entryId всегда уникален внутри группы.

Пример: entryId "1111" принадлежит group1, group2, group3.Я использую старый способ Java 7 для перебора списков и проверки.Есть ли какой-либо наилучший способ использования Java8 Collectors / grouping для достижения этого.

List<Group>, где каждый объект группы будет иметь список объектов Entry.

    [  
   {  
      "id":"group1",
      "entries":[  
         {  
            "entryId":"1111",
            "name":"test1"
         },
         {  
            "entryId":"2222",
            "name":"test2"
         },
         {  
            "entryId":"3333",
            "name":"test3"
         }
      ]
   },
   {  
      "id":"group2",
      "entries":[  
         {  
            "entryId":"4444",
            "name":"test1"
         },
         {  
            "entryId":"1111",
            "name":"test2"
         },
         {  
            "entryId":"2222",
            "name":"test3"
         }
      ]
   },
   {  
      "id":"group3",
      "entries":[  
         {  
            "entryId":"1111",
            "name":"test1"
         },
         {  
            "entryId":"5555",
            "name":"test2"
         },
         {  
            "entryId":"3333",
            "name":"test3"
         }
      ]
   }
]

Итак, ожидаемый результатэто:

    [  
   {  
      "1111":[  
         "group1",
         "group2",
         "group3"
      ]
   },
   {  
      "2222":[  
         "group1",
         "group2"
      ]
   },
   {  
      "3333":[  
         "group1",
         "group3"
      ]
   },
   {  
      "4444":[  
         "group2"
      ]
   },
   {  
      "5555":[  
         "group3"
      ]
   }
]

Я использую ниже способ в настоящее время.который работает, как и ожидалось, но есть ли гораздо более простой способ в Java 8, я могу достичь этого.

    public Map<String, List<String>> mapEntries(List<Group> groups) {
    Map<String, List<String>> entryMaps = new HashMap<>();
    for (Group group : groups) {
        for (Entry entry : group.getEntries()) {
            List<String> groupsEntryBelongs = new ArrayList<>();
            if (groups.iterator().hasNext() && !entryMaps.keySet().contains(entry.getEntryId())) {
                updateGroups(groups, entry.getEntryId(), groupsEntryBelongs, entryMaps);
            }
        }
    }
    return entryMaps;
}

    void updateGroups(List<Group> groups, String id, List<String> groupsEntryBelongs, Map<String, List<String>> entryMaps) {
        for (Group group : groups) {
            for (Entry entry : group.getEntries()) {
                if (entry.getEntryId().equalsIgnoreCase(id)) {
                    groupsEntryBelongs.add(group.getId());
                }
            }
        }
        entryMaps.put(id, groupsEntryBelongs);
    }

Ответы [ 3 ]

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

Вы можете сделать это следующим образом:

Map<String, Set<String>> entryMaps = new LinkedHashMap<>();
groups.forEach(group -> 
    group.getEntries().forEach(entry -> 
            entryMaps.computeIfAbsent(
                    entry.getEntryId().toLowerCase(),
                    k -> new LinkedHashSet<>())
                .add(group.getId())));

Это повторяет группы, затем записи каждой группы и использует Map.computeIfAbsent, чтобы поместить запись с новым, пустым LinkedHashSet, если ключа не было, возвращая либо этот пустой набор, либо набор, соответствующий этому ключу. Затем идентификатор группы добавляется к этому возвращенному набору.

Примечание: я использую Set вместо List для значений, чтобы избежать возможных дубликатов. И LinkedHashMap и LinkedhashSet гарантируют порядок вставки.

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

Вы можете сделать это так,

Map<String, List<String>> groupIdsByEntryId = groups.stream()
    .flatMap(g -> g.getEntries().stream()
        .map(e -> new AbstractMap.SimpleEntry<>(e.getEntryId(), g.getId())))
    .collect(Collectors.groupingBy(Map.Entry::getKey, TreeMap::new,
        Collectors.mapping(Map.Entry::getValue, Collectors.toList())));

Создать простую запись map для каждой комбинации значений entryId и groupId. Затем используйте коллектор groupingBy, чтобы получить List значений groupId для каждого entryId. Если вам нужно отсортировать по ключам, то передайте TreeMap::new в mapFactory перегрузку оператора.

А вот и вывод,

{1111=[group1, group2, group3], 2222=[group1, group2], 3333=[group1, group3], 4444=[group2], 5555=[group3]}
0 голосов
/ 12 ноября 2018

Что-то вроде этого должно работать, для этого требуется создание какого-то промежуточного объекта кортежа:

list.stream()
.flatMap(group ->
   group.getEntries.stream()
        .map(entry -> new GroupEntry(group.getId(), entry.getEntryId()))
)
.collect(
   Collectors.groupingBy(GroupEntry::getEntryId, Collectors.mapping(GroupEntry::getGroupId, Collectors.toList())));
...