使用流和收集器创建嵌套地图的问题

发布于 2025-01-29 09:11:45 字数 1804 浏览 5 评论 0 原文

class QuizAnswers {
  List<CheckboxAnswer> checkBoxAnswers;
}

class CheckboxAnswer {
  int questionId;
  // The indices of the selected answer choices
  List<Integer> answer_selections;
}

我功能的输入是 list&lt; quizanswers&gt;

我想创建一个 map&lt; integer,map&lt; integer,long&gt;&gt; 映射&lt; chackboxanswer.questionid:&lt; chackboxanswer.answer.answer.answer.answer_selection代码>。换句话说,我想创建一个嵌套地图,将每个多个选择测验问题映射到代表该测验问题的每个答案选择总数的地图。

假设输入 list&lt; quizanswers&gt; quizanswerslist as:

[ {questionId: 1, answer_selection: [1,2]},    
  {questionId: 1, answer_selection:[1,2,3,4]},  
  {questionId: 2, answer_selection:[3]},   
  {questionId: 2, answer_selection:[1]} ]

然后我希望输出为:

{1 : {1:2, 2:2, 3:1, 4:1}, 2: {1:1, 3:1}}

因为 id = 1 接收到答案选择的两个选择 2 1 < /code>和 1 在答案选择上选择 3 4 iD = 2 hate > 1 在答案选择上选择 1 3

我已经尝试过

quizAnswersList.stream()
            .flatMap(
                quizAnswers ->
                    quizAnswers.getCheckboxAnswers().stream())
            .collect(
                answer -> {
                  return Collectors.groupingBy(
                      answer.getQuestionId(),
                      answer.getAnswerSelections().stream()
                          .collect(
                              Collectors.groupingBy(
                                  answerSelection -> answerSelection, 
                                  Collectors.counting())));
                        });

,这给我一个错误,即第一个收集()没有采用正确的论点。

class QuizAnswers {
  List<CheckboxAnswer> checkBoxAnswers;
}

class CheckboxAnswer {
  int questionId;
  // The indices of the selected answer choices
  List<Integer> answer_selections;
}

The input to my function is a List<QuizAnswers>.

I want to create an output of Map<Integer, Map<Integer, Long>> that maps <CheckboxAnswer.questionId : <CheckboxAnswer.answer_selection, total count of answer_selection>. In other words, I want to create a nested map that maps each multiple selection quiz question to a map representing the total number of selections on each answer choice of that quiz question.

Suppose the input List<QuizAnswers> quizAnswersList as:

[ {questionId: 1, answer_selection: [1,2]},    
  {questionId: 1, answer_selection:[1,2,3,4]},  
  {questionId: 2, answer_selection:[3]},   
  {questionId: 2, answer_selection:[1]} ]

Then I would want the output to be:

{1 : {1:2, 2:2, 3:1, 4:1}, 2: {1:1, 3:1}}

Because the question with Id = 1 received two selections on answer choice 2 and 1 and 1 selection on answer choice 3 and 4 while the question with Id=2 had 1 selection on answer choice 1 and 3.

I have tried

quizAnswersList.stream()
            .flatMap(
                quizAnswers ->
                    quizAnswers.getCheckboxAnswers().stream())
            .collect(
                answer -> {
                  return Collectors.groupingBy(
                      answer.getQuestionId(),
                      answer.getAnswerSelections().stream()
                          .collect(
                              Collectors.groupingBy(
                                  answerSelection -> answerSelection, 
                                  Collectors.counting())));
                        });

Which is giving me an error that the first collect() is not taking the right arguments.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

国产ˉ祖宗 2025-02-05 09:11:45

尽管您很接近,但您对收藏家的使用在句法上是不正确的。

首先,必需的方法 collect> collect() 期望收集器(也有另一种味道 collect> collect> collect() 期望树“函数”:供应商,累加器和组合者

.collect(MyCollector);

; .oracle.com/en/java/javase/17/docs/api/java.base/java/java/util/stream/collectors.html#groupingby(java.util.function.function.function.function.function.function.function)“ rel =” nofollow noreforler noreferrer“ noreferrer”> <代码> groupingby() 收集器。我们需要它的版本,它可以期望 classifier 函数和a downstream collector

.collect(Collectors.groupingBy(function, AnotherCollector);

作为下游收集器,我们需要提供 flatmapping() 。期望将每个 checkboxanswer 转换为答案选择值的流) >)和A 下游收集器。依次为 flatmapping()下游再次提供 groupingby() and and counting() as它的下游收集器

收藏家的最终结构将是以下内容:

.collect(Collectors.groupingBy(function, // <- getting a question Id
    Collectors.flatMapping(function,     // <- obtaining `answer selection values` as a stream of Integer
        Collectors.groupingBy(function,  // <- Function.identity() is used to retain a `answer selection` without changes
            Collectors.counting()        // <- obtaining a count for each `answer selection`
);

现在,让我们将所有内容放在一起。

public static void main(String[] args) {
    List<QuizAnswers> quizAnswersList =
        List.of(new QuizAnswers(List.of(new CheckboxAnswer(1, List.of(1,2)),
                                        new CheckboxAnswer(1, List.of(1,2,3,4)))),
                new QuizAnswers(List.of(new CheckboxAnswer(2, List.of(3)),
                                        new CheckboxAnswer(2, List.of(1)))));

    Map<Integer, Map<Integer, Long>> answerSelectionToCountById = quizAnswersList.stream()
        .map(QuizAnswers::getCheckBoxAnswers)
        .flatMap(List::stream)
        .collect(Collectors.groupingBy(
            CheckboxAnswer::getQuestionId,
                Collectors.flatMapping(checkboxAnswer -> checkboxAnswer.getAnswerSelections().stream(),
                    Collectors.groupingBy(Function.identity(),
                        Collectors.counting()))));
    
    answerSelectionToCountById.forEach((k, v) -> System.out.println(k + " : " + v));
}

输出

1 : {1=2, 2=2, 3=1, 4=1}
2 : {1=1, 3=1}

Although you were close, your usage of collectors is syntactically incorrect.

Firstly, the required method collect() expects a collector (there's also another flavor of collect() that expect tree "functions": supplier, accumulator and combiner; don't confuse them), that's the correct syntax:

.collect(MyCollector);

Now, regarding the groupingBy() collector. We need its version that expects a classifier function and a downstream collector:

.collect(Collectors.groupingBy(function, AnotherCollector);

And as a downstream collector we need to provide flatMapping(). Which expects a function that should transform each CheckboxAnswer into a stream of answer selection values (in order to be able to map each of them to its count), and a downstream collector. In turn as the downstream of flatMapping() again we need to provide groupingBy() and counting() as its downstream collector.

The final structure of collectors will be the following:

.collect(Collectors.groupingBy(function, // <- getting a question Id
    Collectors.flatMapping(function,     // <- obtaining `answer selection values` as a stream of Integer
        Collectors.groupingBy(function,  // <- Function.identity() is used to retain a `answer selection` without changes
            Collectors.counting()        // <- obtaining a count for each `answer selection`
);

Now, let's put all the things together.

public static void main(String[] args) {
    List<QuizAnswers> quizAnswersList =
        List.of(new QuizAnswers(List.of(new CheckboxAnswer(1, List.of(1,2)),
                                        new CheckboxAnswer(1, List.of(1,2,3,4)))),
                new QuizAnswers(List.of(new CheckboxAnswer(2, List.of(3)),
                                        new CheckboxAnswer(2, List.of(1)))));

    Map<Integer, Map<Integer, Long>> answerSelectionToCountById = quizAnswersList.stream()
        .map(QuizAnswers::getCheckBoxAnswers)
        .flatMap(List::stream)
        .collect(Collectors.groupingBy(
            CheckboxAnswer::getQuestionId,
                Collectors.flatMapping(checkboxAnswer -> checkboxAnswer.getAnswerSelections().stream(),
                    Collectors.groupingBy(Function.identity(),
                        Collectors.counting()))));
    
    answerSelectionToCountById.forEach((k, v) -> System.out.println(k + " : " + v));
}

Output

1 : {1=2, 2=2, 3=1, 4=1}
2 : {1=1, 3=1}
时光沙漏 2025-02-05 09:11:45

分两个步骤可以更容易地到达最终​​结果:按照质疑进行分组后,您需要将映射到 answers_selections 。可以使用 collector.mapping 来完成此操作类似:

Map<Integer, List<List<Integer>>> intermediate =
        quizAnswersList.stream()
                .flatMap(quizAnswers -> quizAnswers.getCheckBoxAnswers().stream())
                .collect(Collectors.groupingBy(CheckboxAnswer::getQuestionId,
                                Collectors.mapping(CheckboxAnswer::getAnswer_selections, Collectors.toList())));

System.out.println(intermediate);

这将为您提供类似的输出:

{1=[[1, 2], [1, 2, 3, 4]], 2=[[3], [1]]}

由于以上不是您真正想要的,因此您需要再做一个步骤并包装在此处完成的映射

Collectors.mapping(CheckboxAnswer::getAnswer_selections, Collectors.toList())

。上述映射的值,即列表的类型列表的类型列表列出到 map&lt; integer,long&gt; ,可以如下所示(包括上述步骤,这仅对解释中间结果有用,仅是有用的需要以下代码):

Map<Integer, Map<Integer, Long>> finalresult =
quizAnswersList.stream()
        .flatMap(quizAnswers -> quizAnswers.getCheckBoxAnswers().stream())
        .collect(Collectors.groupingBy(CheckboxAnswer::getQuestionId,
                Collectors.collectingAndThen(
                        Collectors.mapping(CheckboxAnswer::getAnswer_selections, Collectors.toList()),
                        lists -> lists.stream()
                                .flatMap(List::stream)
                                .collect(Collectors.groupingBy(Function.identity(),Collectors.counting())))));

System.out.println(finalresult);

这将为您带来所需的结果

{1={1=2, 2=2, 3=1, 4=1}, 2={1=1, 3=1}}

It is may be easier to get to the final result in two steps: After grouping by your questionId you need to map to your answer_selections. This can be done using Collectors.mapping so that you end up with an intermediate result of Map<Integer,List<List<Integer>>> which could look like something like:

Map<Integer, List<List<Integer>>> intermediate =
        quizAnswersList.stream()
                .flatMap(quizAnswers -> quizAnswers.getCheckBoxAnswers().stream())
                .collect(Collectors.groupingBy(CheckboxAnswer::getQuestionId,
                                Collectors.mapping(CheckboxAnswer::getAnswer_selections, Collectors.toList())));

System.out.println(intermediate);

This will give you an output like:

{1=[[1, 2], [1, 2, 3, 4]], 2=[[3], [1]]}

Since the above is not what you realy wanted you need to do one more step and wrap the mapping which is done here

Collectors.mapping(CheckboxAnswer::getAnswer_selections, Collectors.toList())

in to Collectors.collectingAndThen to turn the values of above map which are of type list of lists to a Map<Integer,Long> which can be done like showed below (including the above step, which only was useful to explain the intermediate result, only the code below is needed):

Map<Integer, Map<Integer, Long>> finalresult =
quizAnswersList.stream()
        .flatMap(quizAnswers -> quizAnswers.getCheckBoxAnswers().stream())
        .collect(Collectors.groupingBy(CheckboxAnswer::getQuestionId,
                Collectors.collectingAndThen(
                        Collectors.mapping(CheckboxAnswer::getAnswer_selections, Collectors.toList()),
                        lists -> lists.stream()
                                .flatMap(List::stream)
                                .collect(Collectors.groupingBy(Function.identity(),Collectors.counting())))));

System.out.println(finalresult);

which will give you the desired result

{1={1=2, 2=2, 3=1, 4=1}, 2={1=1, 3=1}}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文