java 8 потоковая группировка в коллекцию пользовательского объекта

#java #java-8 #java-stream #collectors

#java #java-8 #java-stream #сборщики

Вопрос:

У меня следующая структура классов

 
public class Store {
    private Long storeId;

    private Long masterStoreId;

    private String operatorIdentifier;
}

public class StoreInfo {

    private String operatorIdentifier;

    private Set<Long> slaveStoreIds;

    public StoreInfo(String operatorIdentifier, Set<Long> slaveStoreIds) {
        super();
        this.operatorIdentifier = operatorIdentifier;
        this.slaveStoreIds = slaveStoreIds;
    }

}
  

Я хочу собрать «Список <Хранилище» в «Карту <Long, StoreInfo>». Возможно ли это сделать за одну операцию / итерацию?

 List<Store> stores;

Map<Long, Set<Long>> slaveStoresAgainstMasterStore = stores.stream().collect(Collectors
                .groupingBy(Store::getMasterStoreId, Collectors.mapping(Store::getStoreId, Collectors.toSet())));

Map<Long, StoreInfo> storeInfoAgainstMasterStore = stores.stream()
                .collect(
                        Collectors
                                .toMap(Store::getMasterStoreId,
                                        val -> new StoreInfo(val.getOperatorIdentifier(),
                                                slaveStoresAgainstMasterStore.get(val.getMasterStoreId())),
                                        (a1, a2) -> a1));


  

Комментарии:

1. Вы действительно хотите Map<Long, StoreInfo> или просто List<StoreInfo> будете работать для вас? .. и вам нужно выяснить (a1, a2) -> a1 , что делает, и заменить его тем, что вы собираетесь выполнять.

2. @Naman я не хочу List<StoreInfo> . Я хочу собрать список StoreID для masterStoreId в пользовательском объекте StoreInfo.

3. Те, у кого одинаковый masterStoreId, имеют одинаковый идентификатор operatorIdentifier?

4. @Rono да, masterStoreId и operatorIdentifier одинаковы

Ответ №1:

Поскольку masterStoreId и operatorIdentifier одинаковы в группе (подтверждено в комментарии), вы можете группировать их, создавая пару из них с помощью AbstractMap.SimpleEntry . Затем с помощью Collectors.toMap create map.

 Map<Long, StoreInfo> storeInfoMap = 
    stores.stream()
          .collect(Collectors.groupingBy(
                      e -> new AbstractMap.SimpleEntry<>(e.getMasterStoreId(),
                                                        e.getOperatorIdentifier()),
                      Collectors.mapping(Store::getStoreId, Collectors.toSet())))
          .entrySet()
          .stream()
          .collect(Collectors.toMap(e -> e.getKey().getKey(),
                            e -> new StoreInfo(e.getKey().getValue(), e.getValue())));
  

Ответ №2:

Чтобы завершить реализацию, вы пытались. Вам необходимо обеспечить возможность слияния в StoreInfo таких :

 public StoreInfo(String operatorIdentifier, Long slaveStoreId) {
    this.operatorIdentifier = operatorIdentifier;
    this.slaveStoreIds = new HashSet<>();
    this.slaveStoreIds.add(slaveStoreId);
}

public static StoreInfo mergeStoreInfo(StoreInfo storeInfo1, StoreInfo storeInfo2) {
    Set<Long> slaveIds = storeInfo1.getSlaveStoreIds();
    slaveIds.addAll(storeInfo2.getSlaveStoreIds());
    return new StoreInfo(storeInfo1.getOperatorIdentifier(), slaveIds);
}
  

это упростит реализацию collector, и вы вызовете их соответствующим образом:

 Map<Long, StoreInfo> storeInfoAgainstMasterStore = stores.stream()
        .collect(Collectors.toMap(Store::getMasterStoreId,
                store -> new StoreInfo(store.getOperatorIdentifier(), store.getStoreId()),
                StoreInfo::mergeStoreInfo));