从2级嵌套列表创建Map,其中键是嵌套列表对象的一部分?

omjgkv6w  于 2022-10-22  发布在  Java
关注(0)|答案(4)|浏览(154)

我有一个简单的嵌套结构:

public static class A {
    private List<B> classBList;

    // constructor, getters, etc.
}

public static class B {
    private int id;
    private String name;

    // constructor, getters, etc.
}

我想创建一个<Integer,List<A>>Map,其中类Bid中的整数字段将是键,输入中包含匹配idA对象将作为值汇总到列表中。输入将是类A的列表。
例如:
输入:

[classBList=[B{id:1, name:"Hello"}, B{id:1, name:"Hi"}, B{id:1, name:"Bye"}, B{id:1, name:"Yes"}],
classBList=[B{id:2, name:"No"}, B{id:2, name:"Go"}, B{id:2, name:"Yellow"}],
classBList=[B{id:2, name:"Joe"}, B{id:2, name:"Blow"}]]

(a对象列表中的3个元素:classBList中的4个元素用于第一个元素,classBLlist中的3元素用于第二个元素,而classBLList中的2个元素用于第三个元素)
classBList中的每个B元素将具有相同的id
输出:

{Key=1, Value=[ A{classBList=[B{id:1, name:"Hello"}, B{id:1, name:"Hi"}, B{id:1, name:"Bye"}, B{id:1, name:"Yes"}]} ]

{Key=2, Value=[ A{classBList=[B{id:2, name:"No"}, B{id:2, name:"Go"}, B{id:2, name:"Yellow"}, B{id:2, name:"Joe"}, B{id:2, name:"Blow"}]} ]

然而,我在编写允许这种情况发生的lambdas时遇到了麻烦。我尝试了什么:

Map<Integer, List<A>> heyThere = classAListInput.stream()
    .collect(Collectors.toMap(
        A::getClass,
        element -> element.getClassBList().stream()
            .map(B::getId)
            .collect(Collectors.toList())
    ));

但这并不能编译,所以不确定语法应该是什么样子。
如果你想知道为什么不改变Map,使其为<Integer,List<B>>,我没有注意到A类中的其他字段,但输出中需要这些字段,这就是为什么A对象的列表将是Map中的值。

toiithl6

toiithl61#

似乎您需要用B的新列表重新构建A类的示例。
但是,预期输出显示列表中只有一个A条目,所有B都添加到同一A示例中:

{Key=2, Value=[ A{classBList=[B{id:2, name:"No"}, B{id:2, name: "Go"}, B{id:2, name:"Yellow"}, B{id:2, name:"Joe"}, B{id:2, name:"Blow"}]} ]

因此,假设A类中有一个接受List<B>的all-args构造函数,可以提供以下实现:

Map<Integer, List<A>> result = classAListInput
    .stream() // Stream<A>
    .flatMap(a -> a.getClassBList().stream()) // Stream<B>
    .collect(Collectors.groupingBy(
        B::getId,
        Collectors.collectingAndThen(
            Collectors.toList(), // List<B> flattening all B instances by id
            lst -> List.of(new A(lst)) // or Arrays.asList or Collections.singletonList
        )
    ));
w80xi6nr

w80xi6nr2#

如果我正确地理解了这个问题,根据样本数据判断,你有一个List<List<B>>作为输入。
根据您提供的示例输出,您需要获得Map<Integer,A>类型的Map(而不是aMap<Integer,List<A>>)。
这可以通过以下步骤完成:

  • 使用flatMap()平坦化数据,即将Stream<List<B>>转换为Stream<B>
  • 通过收集器groupingBy()将元素按id分组;
  • 将Map到相同键的元素收集到一个列表中,并将它们转换为对象A,这可以通过将收集器collectingAndThen()toList()的组合应用于groupingBy()下游来完成。

这就是它的实现方式:

public static void main(String[] args) {
    List<List<B>> classAListInput = List.of(
        List.of(new B(1, "Hello"), new B(1, "Hi"), new B(1, "Bye"), new B(1, "Yes")),
        List.of(new B(2, "No"), new B(2, "Go"), new B(2, "Yellow")),
        List.of(new B(2, "Joe"), new B(2, "Blow"))
    );

    Map<Integer, A> aById = classAListInput.stream()
        .flatMap(Collection::stream)      // flattening the data
        .collect(Collectors.groupingBy(
            B::getId,                     // grouping by id
            Collectors.collectingAndThen(
                Collectors.toList(),      // accumulating elements into a list
                A::new)                   // instantiating object A based on the List<B>
        ));

    aById.forEach((id, a) -> System.out.println(id + " -> " + a));
}
  • 输出:*

A link to Online Demo

v8wbuo2f

v8wbuo2f3#

使用Java 8分组依据:

您可以使用groupingBy功能,如下所示:

  • 这里*

1.我使用flatMap()将所有数据列表合并为一个列表。
1.我用id作为分组元素使用groupingBy(),然后在收集数据之前,我用Collectors.mapping()将数据转换为List<A>

B、 java语言

public class B {
    private int id;
    private String name;

    public B(int id, String name) {
        this.id = id;
        this.name = name;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @Override
    public String toString() {
        return "B{" +
                "id=" + id +
                ", name='" + name + '\'' +
                '}';
    }
}

A、 java语言

public class A {
    private List<B> classBList;

    public A(List<B> classBList) {
        this.classBList = classBList;
    }

    public List<B> getClassBList() {
        return classBList;
    }

    public void setClassBList(List<B> classBList) {
        this.classBList = classBList;
    }

    @Override
    public String toString() {
        return "A{" +
                "classBList=" + classBList +
                '}';
    }
}

测试.java

public class Test {
    public static void main(String[] args) {

        List<List<B>> listInput = List.of(
                List.of(new B(1, "Hello"), new B(1, "Hi"), new B(1, "Bye"), new B(1, "Yes")),
                List.of(new B(2, "No"), new B(2, "Go"), new B(2, "Yellow")),
                List.of(new B(2, "Joe"), new B(2, "Blow"))
        );

       Map<Integer,List<A>> output =
           listInput.stream().flatMap(Collection::stream)
                   .collect(Collectors.groupingBy(B::getId,
                           Collectors.mapping(x -> 
                                   new A(List.of(new B(x.getId(), x.getName())))
                                   ,Collectors.toList())));

        System.out.println(output);
    }
}

输出:

{1=[A{classBList=[B{id=1, name='Hello'}]}, A{classBList=[B{id=1, name='Hi'}]}, A{classBList=[B{id=1, name='Bye'}]}, A{classBList=[B{id=1, name='Yes'}]}],

2=[A{classBList=[B{id=2, name='No'}]}, A{classBList=[B{id=2, name='Go'}]}, A{classBList=[B{id=2, name='Yellow'}]}, A{classBList=[B{id=2, name='Joe'}]}, A{classBList=[B{id=2, name='Blow'}]}]}
smtd7mpg

smtd7mpg4#

您需要平面Map到某种元组类,如AbstractMap.SimpleEntry,这样您就可以并行地对AB进行流处理,然后反转分组:

classAListInput.stream()
        .flatMap(a -> a.getClassBList()
                .stream()
                .map(b -> new SimpleEntry<>(b.getId(), a)))
        .collect(groupingBy(Entry::getKey, mapping(Entry::getValue, toList())))

相关问题