代码之家  ›  专栏  ›  技术社区  ›  Maths noob

在groovy中展平嵌套映射

  •  3
  • Maths noob  · 技术社区  · 6 年前

    假设我有以下结构:

    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 等?

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

    4 回复  |  直到 5 年前
        1
  •  2
  •   Michael Easter    6 年前

    关于另一个问题(并附和@damahapatro的评论),请考虑以下问题。

    给出两个列表:

    def list1 = ['x', 'y', 'z']
    def list2 = ['a', 'b', 'c']
    

    还有一个函数 f 给出适当的值,然后我们可以使用 inject (它将在遍历组合时累积一个映射(例如 [x,a] )以下内容:

    def m = [list1, list2].combinations().inject([:]) { map, combo ->
        assert combo.size() == 2
        def a = combo[0]
        def b = combo[1]
        map["${a}-${b}" as String] = f(a,b)
        map
    }
    
    assert m == [
    "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
    ]
    
        2
  •  3
  •   Paul Walkington    6 年前

    您可以创建一个递归函数,该函数将在映射上循环并将其展平。

    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)​
    
        3
  •  1
  •   tim_yates    6 年前

    另一种从头开始绘制地图的方法是:

    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))]
        }
    
        4
  •  0
  •   Valdi_Bo    6 年前

    你可以用一个 单一的 结构:

    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
    

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