【问题标题】:Best way to code this, string to map conversion in Groovy最好的编码方式,Groovy 中的字符串到映射转换
【发布时间】:2011-02-18 06:05:22
【问题描述】:

我有一个类似的字符串

def data = "session=234567893egshdjchasd&userId=12345673456&timeOut=1800000"

我想把它转换成地图

 ["session", 234567893egshdjchasd]
 ["userId", 12345673456]
 ["timeout", 1800000]

这是我目前的做法,

 def map = [:]

 data.splitEachLine("&"){

   it.each{ x ->

     def object = x.split("=")
     map.put(object[0], object[1])

   }

 }

有效,但有没有更有效的方法?

【问题讨论】:

    标签: string groovy map


    【解决方案1】:

    我不知道这是否会运行得更快,但它确实在句法简约方面表明了自己:

    def data = 'session=234567893egshdjchasd&userId=12345673456&timeOut=1800000'
    def result = data.split('&').inject([:]) { map, token -> 
        //Split at "=" and return map with trimmed values
        token.split('=').with { 
            map[it[0].trim()] = it[1].trim() 
        }
        map 
    }
    

    就我个人而言,我喜欢 Don 对可读性和可维护性的回答,但根据上下文,这可能是合适的。

    编辑:这实际上是一个重新格式化的单行。

    【讨论】:

    • +1 用于使用花哨的 GDK 方法(注入)和花哨的英语短语(句法简约)
    • 如果你 真的 讨厌可读性 ;-)
    • 我喜欢这个解决方案——直到我发现有一个“collectEntries()”函数可以用来构建地图。这比“inject()”更具可读性,请参阅下面的答案。
    【解决方案2】:

    我不知道这是否更有效,但在我看来,它更简单一些(YMMV)

    def data = "session=234567893egshdjchasd&userId=12345673456&timeOut=1800000"
    def map = [:]
    
    data.split("&").each {param ->
        def nameAndValue = param.split("=")
        map[nameAndValue[0]] = nameAndValue[1]
    }
    

    【讨论】:

    • 我写了一个快速而肮脏的 Groovy 脚本(可能有相当大的缺陷),比较了上面提到的 3 种技术,并且一致地,Dons 方法出现得最快。它抓取了 3 个不同长度的查询字符串,并为每种方法计时了多长时间,输出例如:Method 1 (ig0774) [124727794, 2236178, 4806756] total: 131770728 Method 2 (Don) [2546134, 1174801, 2227867] total: 5948802 Method 3 (Ted Naleid) [10447068, 1915955, 2840445] total: 15203468 Good enough for my purpose
    【解决方案3】:

    如果您正在寻找高效的正则表达式:

    def data = "session=234567893egshdjchasd&userId=12345673456&timeOut=1800000"
    def map = [:]
    data.findAll(/([^&=]+)=([^&]+)/) { full, name, value ->  map[name] = value }
    
    println map
    

    打印:

    [session:234567893egshdjchasd, userId:12345673456, timeOut:1800000]
    

    如果你不熟悉正则表达式,它可能看起来有点陌生,但实际上并没有那么复杂。它只有两个(组),第一组是除“&”或“=”之外的任何字符。第二组是除“=”之外的任何字符。捕获组位于“=”的任一侧。

    【讨论】:

    • 这是一个不错的解决方案,但可以通过使其成为功能性单线器来变得更好: data.findAll(/([^&=]+)=([^&]+)/ ) { full, name, value -> [name, value] }.collectEntries( { it })
    【解决方案4】:

    经过一番搜索,“collectEntries()”是一个神奇的东西,它创建了一个地图元素。就像创建列表的“collect()”一样工作。所以给定

    def params = "a1=b1&a2=b2&a3&a4=&a5=x=y"
    

    单行是

    map = params.tokenize("&").collectEntries{ 
              it.split("=",2).with{ 
                  [ (it[0]): (it.size()<2) ? null : it[1] ?: null ] 
              }
          }
    

    创造

    map = [a1:b1, a2:b2, a3:null, a4:null, a5:x=y]
    

    根据您希望如何处理“a3”和“a4=”的情况,您还可以使用稍短的版本

    ...
    [ (it[0]): (it.size()<2) ? null : it[1] ] 
    ...
    

    然后你得到这个:

    map = [a1:b1, a2:b2, a3:null, a4:, a5:x=y]
    

    【讨论】:

      【解决方案5】:

      如果你在一个 grails 控制器中,那么这很简单:

      GrailsParameterMap map = new GrailsParameterMap(request)
      

      http://grails.org/doc/latest/api/org/codehaus/groovy/grails/web/servlet/mvc/GrailsParameterMap.html

      【讨论】:

        【解决方案6】:

        如果你使用 Grails,我发现最好的方法是 WebUtils 函数 fromQueryString。

        https://grails.github.io/grails-doc/2.0.x/api/org/codehaus/groovy/grails/web/util/WebUtils.html

        【讨论】:

          【解决方案7】:

          这是我的努力,一次初始化并填充地图,并避免了我个人觉得难以遵循的注入方法:-

              def map = data.split('&').collectEntries {
                  def kvp = it.split('=').collect { string ->
                      string = string.trim()
                      return string
              }
              [(kvp[0]): kvp.size() > 1 ? kvp[1] ?: '' : '']
              // the null check is almost certainly overkill so you could use :-
              // [(kvp[0]): kvp.size() > 1 ? kvp[1] : '']
              // this just checks that a value was found and inserts an empty string instead of null 
          }
          

          【讨论】:

            【解决方案8】:

            我根本不建议使用 split。

            Split 创建一个新字符串,而在创建环境变量集合时,您可能需要一个映射列表。

            在初始中断 (&) 和嵌套中断 (=) 上都进行标记。虽然大多数解释器仍然可以工作,但有些解释器可能会按字面意思运行拆分,您最终会得到一个字符串列表,而不是映射列表。

            def data= "test1=val1&test2=val2"
            def map = [:]
            
            map = data.tokenize("&").collectEntries {
                it.tokenize("=").with {
                    [(it[0]):it[1]]
                }
            }
            

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 2014-03-10
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2014-05-26
              • 2017-01-16
              • 2016-04-17
              • 2012-09-09
              相关资源
              最近更新 更多