创建一个包含计数的映射的映射,来自列表

huangapple go评论65阅读模式
英文:

Create a map of maps with counts from list

问题

给定一个 List<Integer> l 和一个因子 int f,我想要使用流来创建一个 Map<Integer, Map<Integer, Long>> m,其中父映射的键是在 l 中索引除以 f 得到的,值是一个将值映射到计数的映射。

如果列表是 {1,1,1,4},而因子是 f=2,我想要得到:

0 -> 
  {
   1 -> 2
  }
1 -> 
  {
   1 -> 1
   4 -> 1
  }

基本上,我希望得到一个流版本的以下操作:

Map<Integer, Map<Integer, Long>> m = new HashMap<>();
for (int i = 0; i < l.size(); i++) {
 m.computeIfAbsent(i/f, k -> new HashMap<>())
  .compute(l.get(i), (k, v) -> v==null?1:v+1);
}

我意识到这与关于收集嵌套映射的问题非常相似,我了解如何执行更简单的 groupingBy 操作来计数:

Map<Integer, Long> m = l.stream()
 .collect(Collectors.groupingBy(Function.identity(), Collectors.counting()));

但我不知道如何将这两个想法结合起来而不进行迭代。

由于我使用索引作为其中一个键,我想,与其从 l.stream() 开始,不如从 IntStream.range(0, l.size()).boxed() 开始,这让我可以得到第一个键(i -> i/f)和第二个键(i -> l.get(i)),但我仍然不知道如何正确地收集计数。

英文:

Given a List<Integer> l and a factor int f, I would like to use a stream to create a Map<Integer, Map<Integer, Long>> m such that the parent map has keys that are the index within l divided by f, and the value is a map of values to counts.

If the list is {1,1,1,4} and the factor is f=2 I would like to get:

0 -> 
  {
   1 -> 2
  }
1 -> 
  {
   1 -> 1
   4 -> 1
  }

Basically, I'm hoping for a stream version of:

Map<Integer, Map<Integer, Long>> m = new HashMap<>();
for (int i = 0; i < l.size(); i++) {
 m.computeIfAbsent(i/f, k -> new HashMap<>())
  .compute(l.get(i), (k, v) -> v==null?1:v+1);
}

I realize it is fairly similar to this question about collecting a map of maps and I understand how to do a much simpler groupingBy with a count:

Map<Integer, Long> m = l.stream()
 .collect(Collectors.groupingBy(Function.identity(), Collectors.counting()));

But I do not understand how to put those two ideas together without iterating.

Because I am working with indexes as one of the keys, I imagine that rather than starting with l.stream() I will start with IntStream.range(0, l.size()).boxed() which lets me get the first key (i -> i/f) and the second key(i -> l.get(i)), but I still don't know how to properly collect the counts.

答案1

得分: 2

以下是翻译好的代码部分:

这是一个解决方案

public static void main(String[] args) {
    final List<Integer> l = List.of(1, 1, 1, 4);
    final int f = 2;

    final var value = IntStream.range(0, l.size())
            .boxed()
            .collect(Collectors.groupingBy(i -> i / f, Collectors.groupingBy(l::get, Collectors.counting())));

    System.out.println(value);
}

不确定是否这是个人要求但有时使用标准循环而不是流可能并不是一件坏事
英文:

Here is a solution.

public static void main(String[] args) {
   final List&lt;Integer&gt; l = List.of(1,1,1,4);
   final int f = 2;

   final var value = IntStream.range(0,l.size())
    .boxed()
    .collect(Collectors.groupingBy(i -&gt; i/f, Collectors.groupingBy(l::get, Collectors.counting())));

   System.out.println(value);
}

Not sure if this is a personal requirement, but sometime using standard loops over streams is not necessarily a bad thing.

答案2

得分: 1

你可以将你的分组收集器包装在CollectingAndThen收集器中,它接受一个下游收集器和一个完成器函数。在完成器函数中,你可以将值(子列表)修改为一个映射:

List<Integer> list = List.of(1, 1, 1, 4);
int fac = 2;

AtomicInteger ai = new AtomicInteger();

Map<Integer, Map<Integer, Long>> result =
    list.stream()
        .collect(Collectors.groupingBy(
            i -> ai.getAndIncrement() / fac,
            Collectors.collectingAndThen(
                Collectors.toList(), val -> val.stream()
                                               .collect(Collectors.groupingBy(Function.identity(),
                                                                              Collectors.counting())))));

System.out.println(result);
英文:

You can wrap your grouping collector in CollectingAndThen collector which takes a downstream collector and a finisher function. In the finisher you can modify the values (sublists) to a map:

List&lt;Integer&gt; list = List.of(1, 1, 1, 4);
int fac = 2;

AtomicInteger ai = new AtomicInteger();

Map&lt;Integer,Map&lt;Integer,Long&gt;&gt; result =
list.stream()
    .collect(Collectors.groupingBy(
            i -&gt; ai.getAndIncrement() / fac,
            Collectors.collectingAndThen(
                    Collectors.toList(), val -&gt; val.stream()
                                                   .collect(Collectors.groupingBy(Function.identity(),
                                                                                  Collectors.counting())))));

System.out.println(result);

huangapple
  • 本文由 发表于 2023年2月7日 04:45:34
  • 转载请务必保留本文链接:https://go.coder-hub.com/75366402.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定