如何对Java列表进行分区以获得一个具有特定条件的列表&;其他的都是交叉的?
如何划分如何对Java列表进行分区以获得一个具有特定条件的列表&;其他的都是交叉的?,java,java-8,java-stream,Java,Java 8,Java Stream,如何划分Java列表以获得以下两种类型的列表: 包含满足特定条件的元素的列表 包含所有元素的列表,但它们将是彼此的交点 我目前的工作方法是使用forEach,如下所示: Map<String, Set<Attribute>> applicableAttributeMap = new HashMap<>(); Set<Attribute> unionMandatoryAttributes = new HashSet<>(); Set&l
Java列表
以获得以下两种类型的列表:
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);
如何创建映射图
,以满足工作方法或任何其他简化解决方案中给出的条件
(注意:所以我的目标是实现工作方法的确切效果,我在解释问题时可能遗漏了一些东西。但底线是通过使用
分区方法或任何比我所做的更好的方法来获得与工作方法相同的结果。)在评论指出我误读了这个问题后编辑
我的修订解决方案:
实际上,如果只是在流外部初始化集合,大部分情况下都可以与流相交。像这样:
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 intersected=new HashSet();
givenNames.stream()
.map(gn->getAllApplicationAttributes(gn))//根据给定名称生成列表流
.forEach(列表->{
if(intersected.isEmpty()){
相交。添加全部(列表);
}否则{
intersected.removeIf(x->!list.contains(x));//如果此迭代中不存在属性,则删除属性
}
});
正如前面提到的,过滤比分区更有意义
Set<Attribute>> unionMandatory = givenNames
.stream()
.flatMap(s -> getAllApplicableAttributes(s).stream())
.filter(Attribute::getIsRequired)
.collect(Collectors.toSet())
Set>unionMandatory=givenNames
.stream()
.flatMap->getAllApplicableAttributes.stream()
.filter(属性::getIsRequired)
.collect(收集器.toSet())
由于流无法创建相交的,,因此从流创建最终的映射是没有意义的,因此我会像您在工作方法中那样将这两个集合放入映射中。在给定名称上迭代两次看起来是最好的方法:
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);
}
Map applicatableattributemap=newhashmap();
List givenNames=ImmutableList.copyOf(..);
设置unionMandatoryAttributes=
givenNames.stream()
.map(this::getAllApplicableAttributes)
.flatMap(集合::流)
.filter(属性::getIsRequired)
.collect(收集器.toSet());
设置IntersectedAttribute=ImmutableSet.of();
如果(givenNames.size()>0){
IntersectedAttribute=this.getAllApplicableAttributes(givesNames.get(0));
for(int i=1;i
请注意,此代码依赖于Guava的ImmutableList
、ImmutableSet
和Sets.intersection
还要注意,在此代码中,对getAllApplicableAttributes
的调用次数增加了一倍。IntersectedAttribute
不会与所有集合相交,因为只有当集合为空时,您才会添加新项,然后可能会根据与下一个列表元素的相交从中删除。我认为需要删除if(intersectedAttributes.isEmpty()){
这一行,但是你说这是有效的解决方案,所以也许可以尝试重新定义你的目标。你可以看到,在if块之后,我正在执行intersectedAttributes.retainal(applicatableattributes)
addAll
将仅在第一次执行,或者intersectedAttributes
列表为空。以后将执行retainal
。我认为这没有任何问题。因此,我的目标是实现工作方法的确切效果。我可能在解释问题时遗漏了一些内容。但是m行是使用partitioning by
或任何其他stream
相关函数获得结果。我已经更新了我的问题,以简要说明我的最终目标。@AshwinK-我认为@Ilya Gazman的问题是对的。或者你是说如果retainal
碰巧删除了所有内容,那么你希望从intersectio开始重新?您当前的方法不起作用。intersectedAttributes
可能会由于retainAll
操作而变为空,因为所有集合都没有公共属性,然后,您会突然对下一个集合执行addAll
,并可能最终得到一个非空集合,其中交集应该是空的。这就是IMHO与要求相差甚远。它满足联合属性要求,但在交叉属性要求上完全失败。交叉属性应为a/交叉b/包含属性,无论是否需要/不需要。在我看来,您只有那些不需要的属性,并且完全缺少交叉点。Except用于删除过时的collector.mapping(Function.identity(),…)
,这正是OP在问题中已经发布的内容。结果是一样的。它甚至在太晚的时候使用.filter(Objects::nonNull)
,就像getAllApplicableAttributes(s)一样
返回null
,对其调用stream()
的尝试将失败,出现NullPointerException
@Holger-它可能会实现OP的分区方法,但如果它没有完成工作方法,如果您是正确的,NullPointerException
可能会返回null&w
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);
}