简体   繁体   English

内联条件 Map Groovy 中的文字

[英]Inline Conditional Map Literal in Groovy

Working on some translation / mapping functionality using Maps/JsonBuilder in Groovy.在 Groovy 中使用 Maps/JsonBuilder 处理一些翻译/映射功能。

Is is possible (without creating extra code outside of the map literal creation).. to conditionally include/exclude certain key/value pairs?有可能(无需在 map 文字创建之外创建额外代码).. 有条件地包含/排除某些键/值对吗? Some thing along the lines of the following..以下是一些事情..

 def someConditional = true   

 def mapResult = 
        [
           "id":123,
           "somethingElse":[],
           if(someConditional){ return ["onlyIfConditionalTrue":true]}
        ]

Expected results: If someConditional if false, only 2 key/value pairs will exist in mapResult.预期结果:如果 someConditional if false,mapResult 中将只存在 2 个键/值对。

If someConditional if true, all 3 key/value pairs will exist.如果 someConditional 如果为真,则所有 3 个键/值对都将存在。

Note that I'm sure it could be done if I create methods / and split things up.. for to keep things concise I would want to keep things inside of the map creation.请注意,如果我创建方法/并将其拆分,我确信它可以完成。为了保持简洁,我希望将内容保留在 map 创建中。

You can help yourself with with : 你可以帮助自己与with

[a:1, b:2].with{
    if (false) {
        c = 1
    }
    it
}

With a small helper: 有一个小帮手:

Map newMap(m=[:], Closure c) {
    m.with c
    m
}

Eg: 例如:

def m = newMap {
    a = 1
    b = 1
    if (true) {
        c = 1
    }
    if (false) {
        d = 1
    }
}

assert m.a == 1
assert m.b == 1
assert m.c == 1
assert !m.containsKey('d')

Or pass an initial map: 或传递初始地图:

newMap(a:1, b:2) {
    if (true) {
        c = 1
    }
    if (false) {
        d = 1
    }
}

edit 编辑

Since Groovy 2.5, there is an alternative for with called tap . 由于Groovy的2.5,存在一种替代with称为tap It works like with but does not return the return value from the closure, but the delegate. 它的工作原理with类似with但不返回闭包的返回值,而是委托。 So this can be written as: 所以可以这样写:

[a:1, b:2].tap{
    if (false) {
        c = 1
    }
}

There is no such syntax, the best you can do is 没有这样的语法,您能做的就是

def someConditional = true   

def mapResult = [        
  "id":123,
  "somethingElse":[]
]

if (someConditional) {
  mapResult.onlyIfConditionalTrue = true
}

I agree with Donal, without code outside of map creation it is difficult. 我同意Donal的观点,没有地图创建之外的代码很难。

At least you would have to implement your own ConditionalMap, it is a little work but perfectly doable. 至少您必须实现自己的ConditionalMap,这虽然有点工作,但是完全可行。

Each element could have it's own condition like 每个元素可以有自己的条件,例如

map["a"] = "A"
map["b"] = "B"
map.put("c","C", true)
map.put("d","D", { myCondition })


   etc...

Here an incomplete example (I did only put , get , keySet , values and size to illustrate, and not typed - but you probably don't need types here?), you will probably have to implement few others (isEmpty, containsKey etc...). 在这里有一个不完整的示例(我只是放置了getkeySet大小来说明,而没有输入-但您这里可能不需要类型?),您可能将不得不实现其他几个(isEmpty,containsKey等)。 ..)。

       class ConditionalMap extends HashMap {

        /** Default condition can be a closure */
        def defaultCondition = true

        /** Put an elemtn with default condition */
        def put(key, value) {
            super.put(key, new Tuple(defaultCondition, value))
        }

        /** Put an elemetn with specific condition */
        def put(key, value, condition) {
            super.put(key, new Tuple(condition, value))
        }

        /** Get visible element only */
        def get(key) {
            def tuple = super.get(key)
            tuple[0] == true ? tuple[1] : null
        }

        /** Not part of Map , just to know the real size*/
        def int realSize() {
            super.keySet().size()
        }

        /** Includes only the "visible" elements keys */
        def Set keySet() {
            super.keySet().inject(new HashSet(),
                    { result, key
                        ->
                        def tuple = super.get(key)
                        if (tuple[0])
                            result.add(key)
                        result
                    })
        }

        /** Includes only the "visible" elements keys */
        def Collection values() {
            this.keySet().asCollection().collect({ k -> this[k] })
        }

        /** Includes only the "visible" elements keys */
        def int size() {
            this.keySet().size()
        }
    }

    /** default condition that do not accept elements */
    def map = new ConditionalMap(defaultCondition: false)

    /** condition can be a closure too */
    // def map = new ConditionalMap(defaultCondition : {-> true == false })


    map["a"] = "A"
    map["b"] = "B"
    map.put("c","C", true)
    map.put("d","D", false)

    assert map.size() == 1
    assert map.realSize() == 4

    println map["a"]
    println map["b"]
    println map["c"]
    println map["d"]

    println "size: ${map.size()}"
    println "realSize: ${map.realSize()}"
    println "keySet: ${map.keySet()}"
    println "values: ${map.values()}"

    /** end of script */

You could potentially map all false conditions to a common key (eg "/dev/null" , "" , etc) and then remove that key afterwards as part of a contract. 您可能会将所有错误条件映射到一个公用密钥(例如"/dev/null"""等),然后在以后将其作为合同的一部分删除。 Consider the following: 考虑以下:

def condA = true   
def condB = false   
def condC = false   

def mapResult = 
[
   "id":123,
   "somethingElse":[],
   (condA ? "condA" : "") : "hello",
   (condB ? "condB" : "") : "abc",
   (condB ? "condC" : "") : "ijk",
]

// mandatory, arguably reasonable
mapResult.remove("")

assert 3 == mapResult.keySet().size()
assert 123 == mapResult["id"]
assert [] == mapResult["somethingElse"]
assert "hello" == mapResult["condA"]

You can use the spread operator to do this for for both maps and lists:您可以使用传播运算符为地图和列表执行此操作:

def t = true

def map = [
    a:5,
    *:(t ? [b:6] : [:])
]

println(map)
[a:5, b:6]

This works in v3, haven't tried in prior versions.这在 v3 中有效,在以前的版本中没有尝试过。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM