如何对Java List
进行分区以获取以下两种类型的列表:
我当前的工作方法正在使用forEach
,如下所示:
Map<String, Set<Attribute>> applicableAttributeMap = new HashMap<>();
Set<Attribute> unionMandatoryAttributes = new HashSet<>();
Set<Attribute> intersectedAttributes = new HashSet<>();
givenNames.forEach(givenName -> {
List<Attribute> applicableAttributes = getAllApplicableAttributes(givenName); //function to retrieve List<Attribute> by passing givenName
if (applicableAttributes != null && !applicableAttributes.isEmpty()) {
unionMandatoryAttributes.addAll(
applicableAttributes
.stream()
.filter(Attribute::getIsRequired)
.collect(Collectors.toSet())
);
if (intersectedAttributes.isEmpty()) {
intersectedAttributes.addAll(applicableAttributes);
}
intersectedAttributes.retainAll(applicableAttributes);
}
});
applicableAttributeMap.put(UnionMandatory, unionMandatoryAttributes);
applicableAttributeMap.put(IntersectedAll, intersectedAttributes);
我正在尝试使用partitioningBy
来简化上述代码块,但无法获得所需的输出。我无法收集包含所有元素以及Map
的{{1}}作为key
的另一个列表。
这是我的String
方法:
partitioningBy
如何创建Map<Boolean, Set<Attribute>> applicableMap = givenNames
.stream()
.flatMap(s -> getAllApplicableAttributes(s).stream())
.filter(Objects::nonNull)
.collect(Collectors.partitioningBy(
Attribute::getIsRequired,
Collectors.mapping(Function.identity(),Collectors.toSet())
));
来满足工作方法中给出的条件或任何其他简化的解决方案?
(注意:所以我的目标是准确地了解工作方法所发生的事情。我可能在解释问题时会漏掉一些东西。但最重要的是要获得与工作方法,例如使用Map<String , Set<Attributes>>
之类的方法或比我做的更好的方法。)
答案 0 :(得分:1)
在givenNames
上进行两次迭代似乎是最好的方法:
Map<String, Set<Attribute>> applicableAttributeMap = new HashMap<>();
List<String> givenNames = ImmutableList.copyOf(....);
Set<Attribute> unionMandatoryAttributes =
givenNames.stream()
.map(this::getAllApplicableAttributes)
.flatMap(Collection::stream)
.filter(Attribute::getIsRequired)
.collect(Collectors.toSet());
Set<Attribute> intersectedAttributes = ImmutableSet.of();
if (givenNames.size() > 0) {
intersectedAttributes = this.getAllApplicableAttributes(givesNames.get(0));
for (int i = 1; i < givenNames.size(); i++) {
intersectedAttributes = Sets.intersection(intersectedAttributes, getAllApplicableAttributes(givesNames.get(i)));
}
}
applicableAttributeMap.put("UnionMandatory", unionMandatoryAttributes);
applicableAttributeMap.put("IntersectedAll", intersectedAttributes);
}
请注意,此代码依赖于番石榴的ImmutableList
,ImmutableSet
和Sets.intersection
。
还要注意此代码中对getAllApplicableAttributes
的调用次数已翻倍。
答案 1 :(得分:-1)
在评论指出我误解了问题后进行了编辑。
我修改后的解决方案:
实际上,如果只在Set之外初始化Set,则实际上可以与Stream进行交集。像这样:
Set<String> intersected = new HashSet<>();
givenNames.stream()
.map(gn -> getAllApplicableAttributes(gn)) // yields Stream of List<Attribute> per given Name
.forEach(list -> {
if ( intersected.isEmpty() ){
intersected.addAll(list);
} else {
intersected.removeIf(x -> !list.contains(x)); // remove attributes if not present in this iteration
}
});
正如上面其他人所提到的,过滤比分区更有意义。
Set<Attribute>> unionMandatory = givenNames
.stream()
.flatMap(s -> getAllApplicableAttributes(s).stream())
.filter(Attribute::getIsRequired)
.collect(Collectors.toSet())
由于intersected
不能由Stream创建,因此从Stream创建最终Map没有意义,所以我将像在工作方法中一样将这两个集合都放入Map中。