Pregunta sobre symbol, json, ruby – Acceso a hashes y matrices Ruby

2

En mi aplicación Rails estoy enviando una cadena JSON compleja que debe decodificarse. Ese no es el problema que sé.

Ahora, antes de implementar todo, estoy intentando acceder a algunas estructuras JSON de ejemplo para ver si puedo acceder a todas las variables. El problema es que los nombres pueden ser variables.

<code>{"configurations" : [ 
{ "drinks" : [
        {"menus" : [
          { "hot" : [
            {"id":15,"unit":"0.33", "price":"1", "currency":"Euro", "position": 4},
            {"id":15,"unit":"0.33", "price":"1", "currency":"Euro", "position": 6}
          ] },

          { "cold" : [
        {"id":15,"unit":"0.33", "price":"1", "currency":"Euro", "position": 4},
            {"id":15,"unit":"0.33", "price":"1", "currency":"Euro", "position": 6}
           ] },

          { "terminals" : [ {"id" : 4}, {"id": 6}, {"id": 7} ] }, 

          { "keys" : { "debit" : "on", "credit": "off" }  }

        ] }
] } ] } 
</code>

Ok, ahora los siguientes camposson variables: "bebidas", "caliente", "frío". Todos los demás campos se llamarán igual.

Ahora me gustaría acceder a cada variable en esta cadena JSON después de que la descifre. Antes de implementarlo, probé un JSON simple:

<code>{"configuration" : [ { "drinks" : [ { "id":15, "unit":"0.33" } ] } ] }
</code>

Después de decodificar en rieles dando como resultado

<code>{ "configuration" => [{"drinks" => [{"id" => 15, "unit" => "0.33" }]}]}
</code>

Ahora como puedo acceder por ejemploid yunit sin usar la palabra "bebidas". La solución también debe ser escalable al ejemplo anterior.

Alguna información adicional: en el JSON grande, debo acceder a todos los elementos que se enumeran allí (los ID), guardarlos en una tabla y devolver el nuevo ID y luego volver a insertarlo en el JSON. (Explicar por qué es necesario hacer esto tomará una página adicional o 4 ^^).

Tu respuesta

3   la respuesta
1

parece un poco extraño tener un hash pero luego no estar interesado en las claves, pero, ¿quién soy yo para juzgar? Es posible que obtengas esos datos extraños de algún otro lugar o algo así.

Dado el ejemplo simplificado anterior, esto es lo que podría hacer:

<code>h["configuration"].first.values.flatten.first 
#=> {"id"=>15, "unit"=>"0.33"}
</code>

Ahora veamos el ejemplo más complicado:

<code>h["configurations"].map(&:values).flatten.first["menus"].map(&:values).flatten.map { |x| x["id"] }.compact
#=> [15, 15, 15, 15, 7]
</code>

Esto devuelve los ID, pero es feo y pierde toda la información de donde vino el ID. Sin ver más de su código, no sé si eso es suficiente o no (probablemente no lo es).

Si el hash se crea por sí mismo, hacerlo menos complicado depende de usted (vea @emboss answer por ejemplo) ;-) Michael Kohl
Gracias, ¿también es posible no perder toda la información de donde proviene la identificación, como usted dijo? Es más que necesito recorrer el hash anterior. También este hash se crea a partir de una forma compleja en jQuery. Corto: hay elementos, terminales y configuraciones. cada terminal tiene una configuración ("bebidas") y puede tener múltiples submenús ("hot", "cold") que tienen hasta 24 elementos (el "id" y así sucesivamente). Es por eso que es tan complicado ^^ DanFritz
1

cada terminal tiene una configuración ("bebidas") y puede tener varios submenús ("hot", "cold") que tienen hasta 24 elementos (el "id" y así sucesivamente)

pero el JSON que publicaste como ejemplo parece reflejar una estructura diferente, eso hace que tu tarea sea innecesariamente difícil, creo. Si JSON preferiría agruparse jerárquicamente de la forma que describió en su comentario, su tarea sería realmente fácil. Parece que tiene la posibilidad de cambiar el JSON que se genera, por lo que le recomiendo que rediseñe su jerarquía en lugar de tratar de escribir / mantener un código que trate con una estructura de datos que no era ideal en primer lugar. .

Como ejemplo, usted dice que un terminal implica su configuración y menús, por lo que pondría los terminales en el nivel superior en lugar de las configuraciones, es decir, convertiría la configuración y los menús en un miembro del terminal en lugar de lo contrario. De esta manera, puede simplemente recorrer todos los terminales, accediendo a sus menús, ID, etc. sin tener que saber que este terminal en particular sirve "bebidas", por ejemplo.

Gracias, sí, mi primera estructura fue así, pero también es posible (probablemente) que 5 terminales tengan la misma configuración. Esto significa que envío 5 veces la misma información a mi servidor, porque estoy tratando de guardar "una configuración" para múltiples terminales, terminé con esta compleja estructura. DanFritz
De acuerdo. Bueno, para evitar duplicados podrías usar referencias. Seguiría agrupando los datos en la jerarquía más conveniente, pero en lugar de duplicar explícitamente los datos, usaría una clave "ref" que apunta a una ID. Luego declara un terminal fuera de la jerarquía. Por lo tanto, se declararía una vez, pero se haría referencia muchas veces: piense en claves externas en una base de datos. emboss
Sí, lo voy a usar como usted dijo, solo múltiples configuraciones (definidas una vez) y luego simplemente vincular los terminales, esto me evita crear imposibles grandes json ^^ DanFritz
3

pero primero que algo anda mal con tu Json, me temo que cuando lo analices, obtienes esto, notarás que, por ejemplo, los terminales no muestran todas las claves. El código aún debe adaptarse para devolver una matriz o hash.

<code>hash = JSON.parse(string) #the string you published
=>

{"configurations"=>
  [{"drinks"=>
     [{"menus"=>
        [{"hot"=>
           [{"id"=>15,
             "unit"=>"0.33",
             "price"=>"1",
             "currency"=>"Euro",
             "position"=>4},
            {"id"=>15,
             "unit"=>"0.33",
             "price"=>"1",
             "currency"=>"Euro",
             "position"=>6}]},
         {"cold"=>
           [{"id"=>15,
             "unit"=>"0.33",
             "price"=>"1",
             "currency"=>"Euro",
             "position"=>4},
            {"id"=>15,
             "unit"=>"0.33",
             "price"=>"1",
             "currency"=>"Euro",
             "position"=>6}]},
         {"terminals"=>{"id"=>7}},
         {"keys"=>{"debit"=>"on", "credit"=>"off"}}]}]}]}
</code>

Aqui el codigo

<code>class Hash
  def dseek(search_key = "", path = "")
    self.each do|key, value|
      if value.is_a?(Hash)
        path += "#{key}."
        value.dseek(search_key, path)
      else
        if value.is_a?(Array)
          path += "#{key}."
          value.each do |val|
            val.dseek(search_key, path)
          end
        else
          puts "#{path}#{key}:#{value}" if search_key === key || search_key === ""
        end
      end
    end
  end
end


hash.dseek
</code>

da

<code>configurations.drinks.menus.hot.id:15
configurations.drinks.menus.hot.unit:0.33
configurations.drinks.menus.hot.price:1
configurations.drinks.menus.hot.currency:Euro
configurations.drinks.menus.hot.position:4
configurations.drinks.menus.hot.id:15
configurations.drinks.menus.hot.unit:0.33
configurations.drinks.menus.hot.price:1
configurations.drinks.menus.hot.currency:Euro
configurations.drinks.menus.hot.position:6
configurations.drinks.menus.cold.id:15
configurations.drinks.menus.cold.unit:0.33
configurations.drinks.menus.cold.price:1
configurations.drinks.menus.cold.currency:Euro
configurations.drinks.menus.cold.position:4
configurations.drinks.menus.cold.id:15
configurations.drinks.menus.cold.unit:0.33
configurations.drinks.menus.cold.price:1
configurations.drinks.menus.cold.currency:Euro
configurations.drinks.menus.cold.position:6
configurations.drinks.menus.terminals.id:7
configurations.drinks.menus.keys.debit:on
configurations.drinks.menus.keys.credit:off
</code>

y

<code>hash.dseek("id")
</code>

da

<code>configurations.drinks.menus.hot.id:15
configurations.drinks.menus.hot.id:15
configurations.drinks.menus.cold.id:15
configurations.drinks.menus.cold.id:15
configurations.drinks.menus.terminals.id:7
</code>
Si lo hace gracias DanFritz
Muchas gracias, he cambiado el JSON por lo que ahora los terminales son una serie de ID. esto funcionara? DanFritz

Preguntas relacionadas