创建Map <string,list <integer>&gt;

时间:2016-04-22 19:43:24

标签: java lambda java-8 java-stream

我正在尝试创建Map<String,List<Integer>>。这里的挑战是如果密钥不存在则创建列表,否则使用当前密钥添加新整数以获取当前列表。 我已经完成了一些非常接近的工作,但我不知道如何参考当前地图来获取列表。

List<String> strList = Arrays.asList(new String[]{"even","odd"});
List<Integer> intList = Arrays.asList(new Integer[]{1,2,3,4,5,6,7});
//This is what i want returned: Map<String, List<Integer>> myMap=null;
List<Map.Entry<String,Integer>> list = strList.stream().flatMap(s -> intList.stream()
.map(i -> Maps.immutableEntry(s,i))).collect(Collectors.toList());

需要通过调用下面的函数来创建值,该函数需要3个参数作为当前键,并且值加上当前列表。:

static public List<Integer> testFunc(String key, Integer i, List<Integer>list){
    if(list == null){
        list = new ArrayList();
    }
    list.add(i * key.hashCode());
    return list;
}

2 个答案:

答案 0 :(得分:3)

实现此行为的最简单方法是将Collectors.groupingBy与您自己的分类器一起使用:

Map<String, List<Integer>> map = 
    intList.stream()
           .collect(Collectors.groupingBy(x -> x % 2 == 0 ? "even" : "odd"));

答案 1 :(得分:0)

你的问题确实需要更清晰。到目前为止你所说的最好的猜测是你有一个键列表,一个输入值列表(整数)一个函数,它接受一个键和一个输入整数,计算一个输出整数并将结果整数添加到一个列表按键映射的值。

听起来你的testFunc必须能够执行各种操作,而不仅仅是“偶数”和“奇怪”。听起来intList中的值可以在多个List中使用,而不仅仅是分区为桶,所以在没有更好的细节的情况下使用我的想象力,我认为它可能看起来像像

static Optional<Integer> testFunc(String key, int intVal){
    switch(key){
        case "even": return Optional.of(intVal).filter(i -> i % 2 == 0);  // return intVal if key is "even" and i is even
        case "odd": return Optional.of(intVal).filter(i -> i % 2 != 0);   // return intVal if key is "odd" and i is odd
        case "pos": return Optional.of(intVal).filter(i -> i > 0);        // return intVal if key is "pos" and i is positive
        case "neg": return Optional.of(intVal).filter(i -> i < 0);        // return intVal if key is "neg" and i is negative
        default: return Optional.empty();
    }
}

我在这里使用Optional因为给定的整数i可能不适用于给定的密钥。如果Optional<Integer>不适用于给定密钥,则过滤器会将Optional.empty()缩减为i

下面的流执行从strList到给定的整数列表的给定键的直接映射。它通过一次一个地考虑每个键,并从intList中选择应用并将它们收集到List的值来实现。

List<String> strList = Arrays.asList("even", "odd", "pos", "neg");
List<Integer> intList = Arrays.asList(-3, -2, -1, 0, 1, 2, 3);
Map<String,List<Integer>> results = strList.stream()
        .collect(Collectors.toMap(s -> s, s -> intList.stream()
                    .map(i -> testFunc(s, i)).filter(Optional::isPresent).map(Optional::get)
                    .collect(Collectors.toList())
            ));
System.out.println(results);

结果是

{neg=[-3, -2, -1], pos=[1, 2, 3], even=[-2, 0, 2], odd=[-3, -1, 1, 3]}

这是你想要的那种结果吗?

我努力解决的一个问题是希望更加清晰,因为你的“偶数”/“奇怪”的例子似乎将一个谓词应用于intList,只为“偶数”过滤偶数,为奇数过滤奇数“;而你的testFunc示例为intList中的每个值为strList中的每个值映射一个值。如果你的testFunc确实需要映射值和过滤器值,那么使用Streams很难做到这一点,因为map()filter()是单独的流操作。如果map()filter()申请了map()Optionalfilter()可以同时执行,{我在上面的示例中执行了操作,然后应用filter(Optional::isPresent)来过滤掉testFunc中不符合布尔测试的内容,然后应用filter(Optional::get)来展开Integer来自Optional包装器。