Java 8中的流(Stream)使用groupingBy进行自定义对象集合分组。

huangapple go评论73阅读模式
英文:

java 8 stream groupingBy into collection of custom object

问题

以下是翻译好的内容:

我有以下的类结构

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;
	}

}

我想将 "List" 收集到一个 "Map<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));


英文:

I have the following class structure


public class Store {
    private Long storeId;

	private Long masterStoreId;

	private String operatorIdentifier;
}

public class StoreInfo {

    private String operatorIdentifier;

	private Set&lt;Long&gt; slaveStoreIds;

	public StoreInfo(String operatorIdentifier, Set&lt;Long&gt; slaveStoreIds) {
		super();
		this.operatorIdentifier = operatorIdentifier;
		this.slaveStoreIds = slaveStoreIds;
	}

}

I want to collect the "List<Store" into a "Map<Long, StoreInfo>". Is it possible to do so in a single operation/iteration?

List&lt;Store&gt; stores;

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

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


答案1

得分: 2

以下是翻译后的内容:

由于在组中masterStoreIdoperatorIdentifier相同(在注释中确认),您可以使用AbstractMap.SimpleEntry创建它们的配对,然后使用Collectors.toMap创建映射。

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())));
英文:

As masterStoreId and operatorIdentifier are same same in group(comfirmed in comment) you can groupingBy both creating pair of them using AbstractMap.SimpleEntry. Then using Collectors.toMap create map.

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

答案2

得分: 1

为了完成这个实现,您正在尝试的部分需要确保在 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);
}

这将简化收集器的实现,并且您可以相应地调用它们:

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

To complete the implementation, you were attempting. You need to ensure merging capability within StoreInfo such as :

public StoreInfo(String operatorIdentifier, Long slaveStoreId) {
    this.operatorIdentifier = operatorIdentifier;
    this.slaveStoreIds = new HashSet&lt;&gt;();
    this.slaveStoreIds.add(slaveStoreId);
}

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

this would simplify the implementation of collector and you an invoke these correspondingly:

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

huangapple
  • 本文由 发表于 2020年9月22日 22:15:48
  • 转载请务必保留本文链接:https://go.coder-hub.com/64011671.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定