Java8, как отфильтровать карту на основе значений из другой карты - PullRequest
0 голосов
/ 31 мая 2019

У меня есть 3 карты, и они настроены следующим образом: -

  //Map1 
  Map<CatalogCd, Set<ItemUID>> availableItems
  //Map2 
  Map<CatalogCd, FilteringPreferences> filteringPrefs
  //Map3 
  Map<ItemUID, ItemInformation> itemDetailInformation

То, что я пытаюсь сделать, это

пройти через availableItems, а затем посмотреть, если ItemInformation дляданный ItemUID совпадает с предпочтениями (по сути, выполняя некоторую проверку предикатов).

Как видно, первые две карты имеют одинаковые ключи, filteringPrefs для одного и того же ключа применяются ко всему наборуэтот ключ catalogcd, любой объект, который не подходит в соответствии с настройкой предикатов в Предпочтениях, должен быть удален из результирующего набора itemuids.

Я заинтересован в создании способа создания потока java 8, map, filterэто выглядит лучше, чем традиционный цикл for на одной карте, а затем вручную удаляет или добавляет элементы к новой карте результатов.

Это традиционный стиль кода для цикла без java-8, который я получил.

public Map<CatalogCd, Set<ItemUID>> filterResponse(Map<CatalogCd, Set<ItemUID>> availableItems,  Map<CatalogCd, FilteringPreferences> filteringPrefs, Map<ItemUID, ItemInformation> itemDetailInformation)
{
    Map<CatalogCd, Set<ItemUID>> resultingFilteredItemsMap = new HashMap<>();
    for(Map.Entry<CatalogCd,FilteringPreferences> catalogCdEntry : filteringPrefs.entrySet()){
    CatalogCd catalogCdInRequest = catalogCdEntry.getKey();
    EnumSet<PrefA> prefA = catalogCdEntry.getValue().getSupportedPrefAs();

    //get set of items for this catalogcd, loop over each itemuid, check from itemDetailInformation map
    //to see if that itemuid's enumset has intersection with the enumset in request's preference.
    Set<ItemUID> itemsForThisCatalogCd = availableItems.get(catalogCdInRequest);
    for(ItemUID item:itemsForThisCatalogCd){
        EnumSet<PrefA> enumSetFromItemInfo = itemDetailInformation.get(item).getPrefAs();
        enumSetFromItemInfo.retainAll(prefA);
        if(!enumSetFromItemInfo.isEmpty()){
            if(resultingFilteredItemsMap.get(catalogCdInRequest)!=null){
                Set<ItemUID> items = resultingFilteredItemsMap.get(catalogCdInRequest);
                items.add(item);
                resultingFilteredItemsMap.put(catalogCdInRequest, items);
            }else{
                resultingFilteredItemsMap.put(catalogCdInRequest, Sets.newHashSet(item));
              }
           }
        }
    }
   return resultingFilteredItemsMap;
}

То, что я до сих пор пробовал, таково: -

availableItems
    .entrySet() 
    .stream() 
    .filter(x- >predicateFilterFactory.createPredicateFilter(filteringPref.get(x.getKey()))) 
    .collect(Collectors.toMap(x->x.getKey(),x->x.getValue));

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

Ответы [ 2 ]

2 голосов
/ 31 мая 2019

Этот метод должен решить вашу проблему:

public static Map<CatalogCd, Set<ItemUID>> filterResponse(Map<CatalogCd, Set<ItemUID>> availableItems, 
            Map<CatalogCd, FilteringPreferences> filteringPrefs, Map<ItemUID, ItemInformation> itemDetailInformation) {
    return filteringPrefs.entrySet().stream()
            .flatMap(e -> availableItems.getOrDefault(e.getKey(), Collections.emptySet())
                    .stream().map(item -> new AbstractMap.SimpleEntry<>(e, item)))
            .filter(e -> itemDetailInformation.get(e.getValue()).getPrefAs().stream()
                    .anyMatch(e.getKey().getValue().getSupportedPrefAs()::contains))
            .collect(Collectors.groupingBy(e -> e.getKey().getKey(), Collectors.mapping(Map.Entry::getValue, Collectors.toSet())));
}

Но я не думаю, что это сделает ваш код более читабельным. Надеюсь, это поможет.

Вы можете просто добавить уже имеющийся оператор filter() сразу после flatMap() или до collect().


РЕДАКТИРОВАТЬ: Вот небольшое объяснение:

  1. flatMap() присоединяется к availableItems на основе клавиш filteringPrefs. Это первая часть вашего первого цикла:
CatalogCd catalogCdInRequest = catalogCdEntry.getKey();
EnumSet<PrefA> prefA = catalogCdEntry.getValue().getSupportedPrefAs();
Set<ItemUID> itemsForThisCatalogCd = availableItems.get(catalogCdInRequest);
for (ItemUID item: itemsForThisCatalogCd) {
    // ...
}
  1. Часть filter() ищет элементы, у которых есть любые префы, доступные в поддерживаемых itemDetailInformation. Это retainAll() и не пустая часть вашего кода.
EnumSet<PrefA> enumSetFromItemInfo = itemDetailInformation.get(item).getPrefAs();
enumSetFromItemInfo.retainAll(prefA);
if (!enumSetFromItemInfo.isEmpty()) {
    // ...
}
  1. Шаг collect() объединяет все элементы обратно в Map<CatalogCd, Set<ItemUID>>, используя оригинальный ключ filteringPrefs и значение availableItems. Это последняя часть вашего кода:
if (resultingFilteredItemsMap.get(catalogCdInRequest) != null) {
    items = resultingFilteredItemsMap.get(catalogCdInRequest);
    items.add(item);
} else {
    items = new HashSet<>(Arrays.asList(item));
}
1 голос
/ 31 мая 2019

Вот, пожалуйста:

public Map<CatalogCd, Set<ItemUID>> filterResponse(Map<CatalogCd, Set<ItemUID>> availableItems,
        Map<CatalogCd, FilteringPreferences> filteringPrefs, Map<ItemUID, ItemInformation> itemDetailInformation) {
    Map<CatalogCd, Set<ItemUID>> resultingFilteredItemsMap = new HashMap<>();
    filteringPrefs.forEach((key, value) -> giveSuitableName(availableItems, itemDetailInformation,
            resultingFilteredItemsMap, key, value));
    return resultingFilteredItemsMap;
}

private void giveSuitableName(Map<CatalogCd, Set<ItemUID>> availableItems,
        Map<ItemUID, ItemInformation> itemDetailInformation, Map<CatalogCd, Set<ItemUID>> resultingFilteredItemsMap,
        CatalogCd catalogCdInRequest, FilteringPreferences filteringPreferences) {
    EnumSet<PrefA> prefA = filteringPreferences.getSupportedPrefAs();

    // get set of items for this catalogcd, loop over each itemuid, check from
    // itemDetailInformation map
    // to see if that itemuid's enumset has intersection with the enumset in
    // request's preference.
    availableItems.get(catalogCdInRequest).stream()
            .map(ai -> collectAndAddItems(itemDetailInformation, resultingFilteredItemsMap, catalogCdInRequest,
                    prefA, ai))
            .filter(s -> !s.isEmpty()).forEach(fs -> resultingFilteredItemsMap.put(catalogCdInRequest, fs));
}

private Set<ItemUID> collectAndAddItems(Map<ItemUID, ItemInformation> itemDetailInformation,
        Map<CatalogCd, Set<ItemUID>> resultingFilteredItemsMap, CatalogCd catalogCdInRequest, EnumSet<PrefA> prefA,
        ItemUID item) {
    EnumSet<PrefA> enumSetFromItemInfo = itemDetailInformation.get(item).getPrefAs();
    enumSetFromItemInfo.retainAll(prefA);
    Set<ItemUID> items = new HashSet<>();
    if (!enumSetFromItemInfo.isEmpty()) {
        if (resultingFilteredItemsMap.get(catalogCdInRequest) != null) {
            items = resultingFilteredItemsMap.get(catalogCdInRequest);
            items.add(item);
        } else {
            items = new HashSet<>(Arrays.asList(item));
        }
    }
    return items;
}
...