2010-05-11 6 views
12

tengo una cadena comomejor manera de codificar esta, cadena para mapear la conversión en Groovy

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

quiero convertirlo en un mapa

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

Ésta es la forma actual que estoy haciendo it,

def map = [:] 

data.splitEachLine("&"){ 

    it.each{ x -> 

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

    } 

} 

Funciona, pero ¿hay una manera más eficiente?

Respuesta

21

No sé que esto se podría correr más rápido, pero lo hace sugerirse en términos de la parsimonia sintáctica:

def data = 'session=234567893egshdjchasd&userId=12345673456&timeOut=1800000' 
def result = data.split('&').inject([:]) { map, token -> 
    token.split('=').with { map[it[0]] = it[1] } 
    map 
} 

Personalmente, me gusta la respuesta de Don para la legibilidad y facilidad de mantenimiento, pero dependiendo del contexto, esto puede ser apropiado.

Editar: Esto es en realidad un formato de un formato reformado.

+3

+1 para el uso de métodos fantasiosos GDK (inyectar) y frases sofisticadas en inglés (parsimonia sintáctica) –

+2

puede cambiar la inyección innards a token.split ('='). con {map << [(it [0]): it [1]]} si realmente odias la legibilidad ;-) –

+0

Me gustó esta solución, hasta que descubrí que hay una función "collectEntries()" que se puede usar para construir mapas. Eso es mucho más legible que el "inyectar()", ver mi respuesta a continuación. –

11

No sé si esto es más eficiente, pero a mis ojos, que es un poco más simple (YMMV)

def data = "session=234567893egshdjchasd&userId=12345673456&timeOut=1800000" 
def map = [:] 

data.split("&").each {param -> 
    def nameAndValue = param.split("=") 
    map[nameAndValue[0]] = nameAndValue[1] 
} 
+2

Escribí una secuencia de comandos Groovy rápida y sucia (posiblemente bastante defectuosa) comparando las 3 técnicas mencionadas y el método de Dons fue el más rápido. Agarró 3 cadenas de consulta de varias longitudes y cronometradas por cuánto tiempo para cada método, por ejemplo: 'Método 1 (ig0774) [124727794, 2236178, 4806756] total: 131770728 Método 2 (Don) [2546134, 1174801, 2227867] total: 5948802 Método 3 (Ted Naleid) [10447068, 1915955, 2840445] total: 15203468' Lo suficientemente bueno para mis propósitos – Steve

5

Si usted está buscando expresiones regulares son eficientes, en donde está:

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

println map 

impresiones:

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

Si usted no está familiarizado con las expresiones regulares, podría parecer un poco extranjero, pero en realidad no es tan complicado. Solo tiene dos (grupos), el primer grupo es cualquier caracter excepto un "&" o un "=". El segundo grupo es cualquier personaje además de un "=". Los grupos de captura están a ambos lados de "=".

1

Aquí está mi esfuerzo, que se inicia y se llena el mapa de una sola vez, y evita el método de inyección que personalmente encuentro difícil de seguir: -

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 
} 
1

Después de algunas búsquedas, "collectEntries() "es lo mágico para usar, crea un elemento de mapa. Trabaja igual que "collect()" que crea una lista.Así que dado

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

la de una sola línea es

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

que crea

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

Dependiendo de cómo desea manejar los casos "A3" y "A4 =" también se puede utilizar una versión ligeramente más corta

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

y luego obtienes esto:

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