【问题标题】:Build a Map from a Set in Groovy在 Groovy 中从集合构建地图
【发布时间】:2014-03-11 12:48:11
【问题描述】:

我们有以下相同类型的 Parent 和 Child 对象的遗留数据结构

Parent1(name1,code1,null)
  Child11(name11,code11,Parent1)
  Child12(name12,code12,Parent1)
Parent2(name2,code2,null)
  Child21(name21,code21,Parent2)
  Child22(name22,code22,Parent2)
etc.

我们有一个旧服务可用,它返回一个包含所有子对象的集合。不返回 Parent 对象,但我们可以为 Set 中的特定 Child 调用 getParent() getter 以获取其 Parent。我们需要从 Groovy 类中调用此服务,然后构建反映原始结构的 Map

def dataMap = [data:[["name":"name1", "code":"code1", 
                         "children":[["name":"name11", "code":"code11"], 
                                     ["name":"name12", "code":"code12"]]], 
                    ["name":"name2", "code":"code2", 
                         "children":[["name":"name21", "code":"code21"], 
                                     ["name":"name22", "code":"code22"]]]]] 

所以基本上 Map 键是父(名称,代码)对,值是各个子对象的(名称,代码)对的列表(地图实际上随后会呈现为 JSON)

作为 Groovy 的新手,我可能可以使用 Java 语法解决这个问题,但我想知道是否有使用 Groovy 特定功能的更简洁的解决方案?任何想法表示赞赏

【问题讨论】:

  • 子节点可以有子节点吗? (即:树可以比一层更深)。另外,你有什么物品?您是否只有一个包含所有孩子和父母的列表?
  • 1.不,孩子们没有其他孩子,所以树 2 中没有更多级别。我不确定我是否正确理解了这个问题,但我们只有提到的遗留方法可用,它返回所有孩子的集合树中的对象;我们必须在该 Set 上循环并使用 childXY.getParent() 来确定特定 Child 的 Parent 来构建 Map
  • 那么你有一个方法可以返回一棵深树的所有叶子节点?

标签: collections map groovy set


【解决方案1】:

据我了解,这是您的设置:

import groovy.transform.*
import groovy.json.*

@TupleConstructor(includeFields=true)
class Node {
    String name
    String code
    private Node parent

    String getParentName() { parent?.name }
    String getParentCode() { parent?.code }
}

def parent1 = new Node( 'name1',  'code1',  null )
def child11 = new Node( 'name11', 'code11', parent1 )
def child12 = new Node( 'name12', 'code12', parent1 )
def parent2 = new Node( 'name2',  'code2',  null )
def child21 = new Node( 'name21', 'code21', parent2 )
def child22 = new Node( 'name22', 'code22', parent2 )

// This is returned by a call to your API
Set nodes = [ child11, child12, child21, child22 ]

然后,您可以执行以下操作(可能还有其他路线,这仅适用于单深度树)

// Get a set of parent nodes
Set parents = nodes.collect { [ name:it.parentName, code:it.parentCode ] }

// Utility closure to return a name and code in a Map
def format = { Node n ->
    [ name: n.name, code: n.code ]
}

// Collect the formatted parents with their formatted children into a Map
def dataMap = [ data:parents.collect { p ->
    p + [ children:nodes.findAll { 
                       it.parentName == p.name && it.parentCode == p.code
                   }.collect { format( it ) } ]
} ]

// Print the JSON representation of this
println new JsonBuilder( dataMap ).toPrettyString()

应该打印出来:

{
    "data": [
        {
            "name": "name2",
            "code": "code2",
            "children": [
                {
                    "name": "name21",
                    "code": "code21"
                },
                {
                    "name": "name22",
                    "code": "code22"
                }
            ]
        },
        {
            "name": "name1",
            "code": "code1",
            "children": [
                {
                    "name": "name11",
                    "code": "code11"
                },
                {
                    "name": "name12",
                    "code": "code12"
                }
            ]
        }
    ]
}

【讨论】:

  • 谢谢你的详细回答,我玩弄了代码,我想我明白了逻辑的主要思想。但是,检查遗留 API(在 Java 中),似乎实际上没有 getParent() 方法,而是只有 getParentName() 和 getParentCode()。这显然似乎暗示 .parent 不能像上面提到的那样。你可以根据这个修改代码吗?提前感谢您,并对原始问题的不准确表示歉意。
  • @hammerfest 试试看 :-)
  • 知道了,再次感谢您;这个问题似乎是你也修改了节点结构,所以对你来说 it.parentName 和 it.parentCode 是有效的语法。然而,在我们的旧节点中是一个 POJO,其中包含字段字符串名称、字符串代码和节点父节点(因为它在您的原始答案中正确使用)以及方法 getName()、getCode()、getParentName() 和 getParentCode() 似乎否认使用 it.parentName 和 it.parentCode :/
  • 奇怪,它应该仍然可以工作,因为 Groovy 应该只调用 getter 来访问属性......你得到了什么错误?
  • @hammerfest 再次更新,希望能更贴近您的情况
猜你喜欢
  • 2019-08-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-12-02
  • 1970-01-01
  • 2017-03-09
  • 2011-09-21
  • 1970-01-01
相关资源
最近更新 更多