拆分地图的键,并使用新键和关联值创建一个新地图

时间:2019-02-18 18:11:38

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

我有一个List中的一个Objects,其中每个人都包含X,Y值(Doubles)和名称String。由于我有多个与坐标对应的同名条目,因此我想将每个名称链接到所有坐标,这是通过创建类型为Map的{​​{1}}

来完成的。

输出示例:

<String, List<Object>>

我现在要做的是在逗号One [[0.1,0.1,0.1],[0.2,0.3,0.4]] One,Two [[0.1,0.1] ,[0.4,0.5]] One,Two,Three [[0.1,0.1] ,[0.6,0.7]] 处拆分名称,并获得以下结果:

,

我的WORKS代码是:

One   [[0.1,0.1,0.1,0.1,0.1,0.1],[0.2,0.3,0.4,0.5,0.6,0.7]]
Two   [[0.01,0.01,0.01,0.01]    ,[0.4,0.5,0.6,0.7]]                    
Three [[0.01,0.01]              ,[0.6,0.7]]

这将创建第一个Map<String, List<Coordinates>> newList = coordinateList.stream() .collect(Collectors.groupingBy(Coordinates::getName));

为了完成第二部分,我尝试了以下方法以及各种组合,但是没有运气:

Map

我得到的错误是:

newList.entrySet().stream()
        .flatMap(entry -> Arrays.stream(entry.getKey().split(","))
                .map(s -> new AbstractMap.SimpleEntry<>(s, entry.getValue())))
        .collect(Collectors.groupingBy(Map.Entry::getKey, 
                Collectors.flatMapping(entry -> entry.getValue().stream(), Collectors.toList())));

请注意,将The method flatMapping((<no type> entry) -> {}, Collectors.toList()) is undefined for the type Collectors 更改为flatMapping可以解决问题,但不能解决问题。

我尝试过的另一种代码变化是:

mapping

仍然没有运气,我经常遇到错误Map<String, List<Object>> collect1 = map.entrySet().stream() .flatMap(entry -> Arrays.stream(entry.getKey().split(",")) .map(s -> new AbstractMap.SimpleEntry<>(s, entry.getValue()))) .collect(groupingBy(Map.Entry::getKey, mapping(Map.Entry::getValue, toList()))) .entrySet().stream() .flatMap(entry -> entry.getValue().stream() .flatMap(Collection::stream) .map(o -> new AbstractMap.SimpleEntry<>(entry.getKey(), o))) .collect(groupingBy(Map.Entry::getKey, mapping(Map.Entry::getValue, toList())));

有什么想法吗?

1 个答案:

答案 0 :(得分:3)

似乎您没有使用java9。如果您使用的是Java9,则使用Collectors.flatMapping的前一种方法将可行。但是我仍然看不到在这里创建新的Map.Entry的任何意义。看看这个解决方案。

private static final Pattern COMMA_DELIMITER = Pattern.compile(",\\s*");

Map<String, Set<Coordinate>> nameToCoordinates = coordinates.stream()
    .flatMap(
        c -> COMMA_DELIMITER.splitAsStream(c.getName())
            .map(n -> new Coordinate(n, c.getX(), c.getY())))
    .collect(Collectors.groupingBy(Coordinate::getName, Collectors.toSet()));

对于每个坐标,获取其名称并使用,分隔符将其分割,然后为每个此类名称标记创建一个具有该新名称和x,y坐标的新坐标。然后只需使用groupingBy收集器收集它即可。由于只需要保留不同的Coordinate值,因此必须在Coordinate类中重写equals和hashCode方法。看起来就是这样。

@Override
public int hashCode() {
    int result = name.hashCode();
    result = 31 * result + Double.hashCode(x);
    result = 31 * result + Double.hashCode(y);
    return result;
}

@Override
public boolean equals(Object obj) {
    return obj instanceof Coordinate && ((Coordinate) obj).getX() == x 
        && ((Coordinate) obj).getY() == y
        && ((Coordinate) obj).getName().equals(name);
}

由于某种原因,如果您确实需要使用第一步中创建的中间图,那么您的解决方案将是这样。

newList.values().stream().flatMap(Collection::stream)
    .flatMap(
        c -> COMMA_DELIMITER.splitAsStream(c.getName())
            .map(n -> new Coordinate(n, c.getX(), c.getY())))
    .collect(Collectors.groupingBy(Coordinate::getName, Collectors.toSet()));

这是输出。

  

{一个= [[名称=一个,x = 0.1,y = 0.2],[名称=一个,x = 0.1,y = 0.4],[名称=一个,   x = 0.1,y = 0.3],[name = One,x = 0.1,y = 0.5],[name = One,x = 0.1,y = 0.6],   [名称=一个,x = 0.1,y = 0.7]],两个= [[名称=两个,x = 0.1,y = 0.4],[名称=两个,   x = 0.1,y = 0.5],[name = Two,x = 0.1,y = 0.6],[name = Two,x = 0.1,y = 0.7]],   Three = [[[name = Three,x = 0.1,y = 0.6],[name = Three,x = 0.1,y = 0.7]]}