转换地图值

时间:2019-12-19 21:42:29

标签: java java-stream

以下问题:

我有一张地图Map<A, List<Integer> map,我想使用流将其转换为Map<A, Double>。要转换它,使用以下技术: 您将列表中的每个元素与下一个元素(最后一个元素与第一个元素)相减,将正结果和负数归为一组(0将被忽略),获得两组的平均值(为两倍)并返回绝对和两个平均值的两倍都将加倍(这将成为结果图的关键)。

例如,您有地图:

A = 30, 40, 50; //here the result would be (A = 30) because 30 - 40 = -10; 40 - 50 = -10; 50 - 30 = 20;
                //that means you calculate average of (-10, -10), which is -10 and average of (20), which is 20 
                //at last you get the absolute sum of those two averages (10 + 20 = 30) 

A1 = 40, 70, 100, 30; //resulting in  (A1 = 93.33333) because average of (-10, -30, -30) is -23.333 and average of (70) is 70

A2 = 100, 100, 110, 120; //resulting in (A2 = 30) because average of (-10, 10) = -10 and average of (20) = 20. 
                         //The zero here (100-100 = 0) will not be regarded 

因此,最后您得到了地图(A = 30,A1 = 83.33333,A2 = 30)。

我现在的问题是我不知道如何计算列表中每个元素之间的差异并将其分组。

2 个答案:

答案 0 :(得分:1)

流不能引用其中的“最后一个元素”或“第一个元素”之类的概念。甚至很难引用“上一个元素”或“下一个元素”,但这正是计算double的工作所在。

因此,您可以将流用于此二维结构的第一阶段,但不能用于第二阶段。您将使用类似的东西:

map.entrySet().stream().collect(Collectors.toMap(
    e -> e.getKey(),
    e -> calculateVoodooValue(e.getValue()));

public double calculateVoodooValue(List<Integer> list) {
    // don't use stream() here. use for (int i = 0; i < idx -1; i++) and the like.
}

答案 1 :(得分:1)

这样做,我相信我发现您的答案之一不正确。总和应为93.333333。

当您说要忽略0时,这意味着如果差值为0,则平均项目数不会增加。

这是完整的信息流答案。最大的警告是它需要Java 12+才能使用Collectors.teeing()

给出以下值映射。

      Map<String, List<Integer>> map = Map.of("A",
            List.of(30, 40, 50),
            "A1",
            List.of(40, 70, 100, 30),
            "A2",
            List.of(100, 100, 110, 120));

结果图在这里计算。

      Map<String, Double> result =
            map.entrySet().stream().collect(Collectors.toMap(Entry::getKey,

从此处开始的所有内容都会计算最终地图条目的双精度值。

     e -> IntStream.range(0,
     e.getValue().size()).mapToDouble(
         n -> e.getValue().get(n % e.getValue().size())- e.getValue().get((n + 1)
                                          % e.getValue().size()))
     .boxed().collect(Collectors.teeing(Collectors.filtering((n -> n < 0),
                    Collectors.averagingDouble(a -> a)),
                                   Collectors.filtering((n -> n > 0),
                    Collectors.averagingDouble(a -> a)),
                               (a, b) -> Math.abs(a)+ Math.abs(b)))));

    System.out.println(result);
  1. entrySet().stream用于从源地图获取原始数据。
  2. e.getValue()是列表,用于通过size来获取列表的get()和单个值
  3. 使用余数运算符根据需要减去值。这样可以从列表中减去最后一个条目。
  4. 这些differences中的每一个都通过teeing()方法发送到两个不同的收集器。第一个收集器对小于0的值进行滤波并取平均值,第二个对大于0的值进行相同的处理。
  5. 然后将这两个收集器的结果作为绝对和相加,得到结果图的两倍。