简体   繁体   English

番石榴:如何定制减少多图?

[英]Guava: how to customly reduce a multimap?

Is the concept of reduce implemented in Guava libs? 是否在Guava库中实现了reduce的概念? I mean I have a multimap: 我的意思是我有一个multimap:

[1] -> 1, 2, 5, 8
[2] -> 3, 6, 4
[3] -> 1, 0

Then I have a multiplying function : 然后我有一个乘法函数

(a, b) -> a * b

And I want to get the following map: 我想得到以下地图:

[1] -> 80          // 1 * 2 * 5 * 8
[2] -> 72          // 3 * 6 * 4
[3] -> 0           // 1 * 0

How do I do it in Guava? 我怎么在番石榴呢?

I don't think there is a reduction operation in Guava. 我不认为番石榴有减少操作。 I guess you have two options. 我想你有两个选择。

If you're using , just stream over the entry set, and collect the entries into a new map with groupingBy and reduce . 如果您正在使用 ,只需在条目集传输,并使用groupingByreduce将条目收集到新地图中。

import static java.util.stream.Collectors.groupingBy;
import static java.util.stream.Collectors.mapping;
import static java.util.stream.Collectors.reducing;

...

Map<Integer, Integer> map = 
    multimap.entries()
            .stream()
            .collect(groupingBy(Map.Entry::getKey,
                                reducing(1, Map.Entry::getValue, (a, b) -> a * b)));

groupingBy as you can guess, will group the entries by their key values. groupingBy ,你可以猜测,将按照键值对条目进行groupingBy Then we just reduce the values grouped (which are Entry<Integer, Integer> ) by first mapping their to their values and finally by multiplying them - providing the identity value which is 1 for the multiplication. 然后我们只是通过首先将它们映射到它们的值并最后将它们相乘来减少分组的值(即Entry<Integer, Integer> ) - 为乘法提供1的标识值。


If you can't use , you can get back a Map<Integer, Collection<Integer>> from your Multimap with Multimaps.asMap and use Maps.transformValues : 如果你不能使用 ,你可以使用Multimaps.asMapMultimap获取Map<Integer, Collection<Integer>>并使用Maps.transformValues

 Map<Integer, Collection<Integer>> tempMap = Multimaps.asMap(oldMap); Map<Integer, Integer> newMap = Maps.transformValues(tempMap, new Function<Collection<Integer>, Integer>() { @Nullable @Override public Integer apply(Collection<Integer> input) { //do the multiplication here return 0; } }); 

Used String key and List<Integer> as values. 使用String键和List<Integer>作为值。

You can also try something like 你也可以尝试类似的东西

    Map<String, List<Integer>> test = new HashMap<String, List<Integer>>();
    test.put("a", Lists.newArrayList(1, 2, 3));
    test.put("b", Lists.newArrayList(4, 5, 6));

    Map<String, Integer> transformEntries = Maps.transformEntries(test, new EntryTransformer<String, List<Integer>, Integer>() {

        @Override
        public Integer transformEntry(String key, List<Integer> values) {
            Integer a = 1;
            for (Integer value : values) {
                a = value * a;
            }
            return a;
        }
    });

    System.out.println(transformEntries);

Result : {a=6, b=120} 结果:{a = 6,b = 120}

Maps.EntryTransformer Maps.EntryTransformer

The easiest way looks like using a stream over entries() , and mapping a function over it that converts the collection to a stream and runs a suitable reduce() function over that. 最简单的方法是在entries()使用流,并在其上映射一个函数,将函数转换为流并运行一个合适的reduce()函数。

Something like this: 像这样的东西:

HashMap<Integer, Integer> collected =
    mmap.entries().stream().collect(HashMap::new,
            (map, e) -> {
                map.put(e.getKey(), e.getValue().stream().reduce((a, b) -> (a * b)).get());
            }, HashMap::putAll);

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

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