Java 8流Map <string,list <string =“” >>每个键的值之和

时间:2018-07-19 17:15:39

标签: java list dictionary java-8 java-stream

我不太熟悉Java 8(仍在学习),并希望了解是否可以使用流找到与以下代码等效的东西。

下面的代码主要尝试为String中的每个值获取对应的double值,然后将其求和。在这种格式下,我找不到任何帮助。我不确定使用流是否会清理代码或使代码更混乱。

// safe assumptions - String/List (Key/Value) cannot be null or empty
// inputMap --> Map<String, List<String>>

Map<String, Double> finalResult = new HashMap<>();
for (Map.Entry<String, List<String>> entry : inputMap.entrySet()) {
    Double score = 0.0;
    for (String current: entry.getValue()) {
        score += computeScore(current);
    }
    finalResult.put(entry.getKey(), score);
}

private Double computeScore(String a) { .. }

5 个答案:

答案 0 :(得分:11)

Map<String, Double> finalResult = inputMap.entrySet()
        .stream()
        .collect(Collectors.toMap(
                Entry::getKey,
                e -> e.getValue()
                      .stream()
                      .mapToDouble(str -> computeScore(str))
                      .sum()));

上面的代码遍历整个地图,并使用相同的键创建一个新的地图;在放置值之前,它首先遍历每个值-这是一个列表,通过在每个列表元素上调用computeScore()计算得分,然后对收集的分数求和,将其加到值中。

答案 1 :(得分:7)

您还可以将forEach方法与流API结合使用以产生所需的结果。

Map<String, Double> resultSet = new HashMap<>();
inputMap.forEach((k, v) -> resultSet.put(k, v.stream()
            .mapToDouble(s -> computeScore(s)).sum()));

s -> computeScore(s)可以更改为使用方法引用,即T::computeScore,其中T是包含computeScore的类的名称。

答案 2 :(得分:3)

这个怎么样?

=IFERROR(
    IF(AND((LEFT($J2,3)="028"),$N2=11),
        "NI Landline",
    IF(AND((LEFT($J2,2)="07"),$N2=11),
        "UK Mobile",
    IF(AND((LEFT($J2,5)="00353"),$N2=14),
        "ROI Number",
    "Other Number")),
="Other Number")

以上版本可以合并为单个Map<String, Double> finalResult = inputMap.entrySet() .stream() .map(entry -> new AbstractMap.SimpleEntry<String, Double>( // maps each key to a new // Entry<String, Double> entry.getKey(), // the same key entry.getValue().stream() .mapToDouble(string -> computeScore(string)).sum())) // List<String> mapped to // List<Double> and summed .collect(Collectors.toMap(Entry::getKey, Entry::getValue)); // collected by the same // key and a newly // calulcated value 方法:

collect(..)

关键部分:

  • collect(..)使用带有Collector的特定策略对元素进行归约。
  • Map<String, Double> finalResult = inputMap.entrySet() .stream() .collect(Collectors.toMap( Entry::getKey, // keeps the same key entry -> entry.getValue() .stream() // List<String> -> Stream<String> // then Stream<String> -> Stream<Double> .mapToDouble(string -> computeScore(string)) .sum())); // and summed Entry::getKey的快捷方式。映射键的功能。
  • entry -> entry.getKey返回entry -> entry.getValue().stream()
  • mapToDouble(..)返回DoubleStream。该操作具有一个汇总操作sum(..),该操作对元素进行求和-一起为Map创建一个新值。

答案 3 :(得分:0)

无论您使用基于流的解决方案还是基于循环的解决方案,这都是有益的,并增加一些清晰度和结构以将内部循环提取到方法中:

private double computeScore(Collection<String> strings) 
{
    return strings.stream().mapToDouble(this::computeScore).sum();
}

当然,这也可以使用循环来实现,但这正是要点:现在可以在外部循环中或在地图条目流的值上调用此方法。

也可以将外部循环或流拉入方法。在下面的示例中,我对此进行了概括:映射键的类型无关紧要。值是List还是Collection实例也是如此。

作为当前接受的答案的替代方法,此处基于流的解决方案不会填充手动创建的新地图。而是使用Collector

(这与其他答案类似,但是我认为提取的computeScore方法大大简化了嵌套流必需的否则难看的lambda)

import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.stream.Collectors;

public class ToStreamOrNotToStream
{
    public static void main(String[] args)
    {
        ToStreamOrNotToStream t = new ToStreamOrNotToStream();

        Map<String, List<String>> inputMap =
            new LinkedHashMap<String, List<String>>();
        inputMap.put("A", Arrays.asList("1.0", "2.0", "3.0"));
        inputMap.put("B", Arrays.asList("2.0", "3.0", "4.0"));
        inputMap.put("C", Arrays.asList("3.0", "4.0", "5.0"));

        System.out.println("Result A: " + t.computeA(inputMap));
        System.out.println("Result B: " + t.computeB(inputMap));
    }

    private <T> Map<T, Double> computeA(
        Map<T, ? extends Collection<String>> inputMap)
    {
        Map<T, Double> finalResult = new HashMap<>();
        for (Entry<T, ? extends Collection<String>> entry : inputMap.entrySet())
        {
            double score = computeScore(entry.getValue());
            finalResult.put(entry.getKey(), score);
        }
        return finalResult;
    }

    private <T> Map<T, Double> computeB(
        Map<T, ? extends Collection<String>> inputMap)
    {
        return inputMap.entrySet().stream().collect(
            Collectors.toMap(Entry::getKey, e -> computeScore(e.getValue()))); 
    }

    private double computeScore(Collection<String> strings) 
    {
        return strings.stream().mapToDouble(this::computeScore).sum();
    }

    private double computeScore(String a)
    {
        return Double.parseDouble(a);
    }

}

答案 4 :(得分:0)

我发现它有点短:

value = startDates.entrySet().stream().mapToDouble(Entry::getValue).sum();