繁体   English   中英

如何在Java列表中按对象的属性分组?

[英]How to group by a property of an object in a Java List?

我有一个资源对象列表。 资源对象定义为:

class Resource {
    String ip;
    String subnet;
    // other properties...
}

我需要一个像地图这样的数据结构,其中键是一个子网中的随机资源,值是其他子网中所有资源的列表。

例如,如果S表示子网, R表示资源,则列表具有:

S1R1, S1R2, S2R1, S2R2, S3R1 and S3R2

预期输出为:

S1R1 -> S2R1, S2R2, S3R1, S3R2
S2R2 -> S1R1, S1R2, S3R1, S3R2
S3R1 -> S1R1, S1R2, S2R1, S2R2

我尝试使用流并收集基于子网的分组,但不确定如何从此处继续。

Map<String, Set<Resource>> grouped = resourceList.stream()
    .collect(Collectors.groupingBy(Resource::getSubnet, Collectors.toSet()));

这不适用于groupingBy收集器,因为它通过将属于某个组的元素传递到每个组的下游收集器来工作,而您不能告诉它传递其他组。

实现您所描述的一种方法是

TreeMap<Resource, Set<Resource>> map
                              = new TreeMap<>(Comparator.comparing(Resource::getSubnet));
for(Resource resource: resourceList)
    map.computeIfAbsent(resource, x -> new HashSet<>(resourceList)).remove(resource);

map.forEach((resource,set) -> System.out.println(resource+" -> "
    +set.stream().map(Resource::toString).collect(Collectors.joining(", "))));

给定列表S1R1, S1R2, S2R1, S2R2, S3R1, S3R2

S1R1 -> S3R2, S2R1, S2R2, S3R1
S2R1 -> S3R2, S1R2, S3R1, S1R1
S3R1 -> S1R2, S2R1, S2R2, S1R1

尽管未定义Set元素的顺序,但实际上并不是随机选择Map的键,它是每个子网中第一个遇到的资源。

您可以通过两个链式流操作来完成此操作

Map<Resource, Set<Resource>> map = resourceList.stream()
    .collect(Collectors.groupingBy(Resource::getSubnet, Collectors.toSet()))
    .values().stream()
    .collect(Collectors.toMap(
        set -> set.iterator().next(),
        set -> {
            Set<Resource> other = new HashSet<>(resourceList);
            other.removeAll(set);
            return other;
        }));

在这里,从每个组中选出的资源确实是未指定的。 与基于TreeMap的方法不同,您必须知道实际的Resource (或尝试全部使用)来查找组。 TreeMap允许使用来自同一子网的任何Resource来查找组。

我不确定子网是如何工作的,但是您必须弄清楚下面的关系( isSubNetOf )。

BiPredicate<Resource, Resource> isSubNetOf = (parent, subnet) -> ???;

Map<Resource, Set<Resource>> resourceToSubnets = resourceList.stream()
        .collect(toMap(
                Function.identity(),
                x -> resourceList.stream().filter(v -> isSubNetOf.test(x, v)).collect(toSet())
                ));

如果需要Map<String, Set<Resource>>Function.identity()更改为所需的Resource::getIpResource::getSubnet

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM