在Groovy中展平嵌套的地图

时间:2018-07-11 14:30:43

标签: groovy

假设我具有以下结构:

Map<String,Map<String,Integer>> nestedMap = [
"x": ["a": 2, "b": 3, "c": 4],
"y": ["a": 20, "b": 30, "c": 40],
"z": ["a": 200, "b": 300, "c": 400]
]

我想弄平这个结构并得到:

[
"x-a" : 2, "x-b" : 3, "x-c" : 4,
"y-a" : 20, "y-b" : 30, "y-c" : 40,
"z-a" : 200, "z-b" : 300, "z-c" : 400
]

如何用collect / collectEnteries等来做到这一点?

或者,您可以看到这些值非常相似。因此,我构造此嵌套地图结构的方法是运行一个遍历[x,y,z]的for循环,并将我的地图的输入项设置为等于遍历[a,b,c]并返回地图的函数。有没有一种方法可以跳过此嵌套结构,并在功能上将元素附加到大地图中?

5 个答案:

答案 0 :(得分:3)

您可以创建一个递归函数,该函数将遍历地图并将其展平。

Map<String,Map<String,Integer>> nestedMap = [
"x": ["a": 2, "b": 3, "z": 4],
"y": ["a": 20, "b": 30, "c": 40],
"z": ["a": 200, "b": 300, "c": 400]
]

String concatenate(String k, String v) {
"${k}-${v}"
}

def flattenMap(Map map) {    
    map.collectEntries { k, v -> 
       v instanceof Map ? 
          flattenMap(v).collectEntries {  k1, v1 -> 
             key = concatenate(k,k1)
            [ (key): v1 ]  
         } :
            [ (k): v ]  
     } 
}


print flattenMap(nestedMap)​

答案 1 :(得分:2)

关于替代问题(并回应@damahapatro的评论),请考虑以下内容。

给出两个列表:

<groupId>CAMM</groupId>
<artifactId>SOM_Enrichment</artifactId>
<version>1.0-SNAPSHOT</version>
<build>
    <plugins>
        <plugin>
            <artifactId>maven-assembly-plugin</artifactId>
            <version>3.1.0</version>
            <configuration>
                <descriptorRefs>
                    <descriptorRef>jar-with-dependencies</descriptorRef>
                </descriptorRefs>
            </configuration>
            <executions>
                <execution>
                    <id>make-assembly</id> <!-- this is used for inheritance merges -->
                    <phase>package</phase> <!-- bind to the packaging phase -->
                    <goals>
                        <goal>single</goal>
                    </goals>
                </execution>
            </executions>
        </plugin>
    </plugins>

</build>

<dependencies>
    <dependency>
        <groupId>com.solacesystems</groupId>
        <artifactId>sol-jcsmp</artifactId>
        <version>[10,)</version>
    </dependency>
</dependencies>

和提供适当值的函数def list1 = ['x', 'y', 'z'] def list2 = ['a', 'b', 'c'] ,然后我们可以使用f(它将在遍历组合(例如inject)时累积映射:

[x,a]

答案 2 :(得分:1)

从头开始构建地图的另一种方法是:

def result = ['a'..'c', 'x'..'z']
    .combinations()
    .collect { a, b -> b + '-' + a }
    .indexed()
    .collectEntries { idx, name ->
        [name, ((idx % 3) + 2) * (int)Math.pow(10, idx.intdiv(3))]
    }

答案 3 :(得分:0)

您可以使用指令来完成任务:

Map<String,Map<String,Integer>> nestedMap = [
  "x": ["a": 2, "b": 3, "c": 4],
  "y": ["a": 20, "b": 30, "c": 40],
  "z": ["a": 200, "b": 300, "c": 400] ]
result = nestedMap.inject([:]){ a, k, v ->
  a << v.collectEntries{ [k + '-' + it.key, it.value] }; a }
println result

(加上设置源数据,再加上打印结果)。

答案 4 :(得分:0)

我修改了@Paul Walkington的define语法并对其进行了测试:

String concatenate(String k, String v) {
    "${k}-${v}"
}

def flattenMap(Map map) {
    map.collectEntries { k, v ->
        v instanceof Map ?
                flattenMap(v).collectEntries {  k1, v1 ->
                    def key = concatenate(k,k1)
                    [ (key): v1 ]
                } :
                [ (k): v ]
    }
}