Frage an ruby, json, symbol – Zugriff auf Hashes und Arrays Ruby

2

In meiner Rails-Anwendung sende ich einen komplexen JSON-String, der dekodiert werden muss. Das ist nicht das Problem, von dem ich weiß, wie.

Bevor ich jetzt alles implementiere, versuche ich, auf einige Beispiel-JSON-Strukturen zuzugreifen, um zu sehen, ob ich auf alle Variablen zugreifen kann. Das Problem ist, dass die Namen variabel sein können.

<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, jetzt die folgenden Feldersind variabel: "Getränke", "heiß", "kalt". Alle anderen Felder werden gleich bezeichnet.

Jetzt möchte ich auf jede Variable in dieser JSON-Zeichenfolge zugreifen, nachdem ich sie dekodiert habe. Vor der Implementierung habe ich ein einfaches JSON ausprobiert:

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

Nach dem Entschlüsseln in Schienen ergibt sich

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

Nun, wie kann ich zum Beispiel zugreifenid undunit ohne das Wort "Getränke" zu verwenden. Die Lösung sollte auch auf das obige Beispiel skalierbar sein.

Einige zusätzliche Informationen: In der großen JSON sollte ich auf alle dort aufgelisteten Elemente zugreifen (die IDs), sie in einer Tabelle speichern und die neue ID zurückgeben und sie dann wieder in die JSON einfügen. (Wenn Sie erklären, warum dies erforderlich ist, benötigen Sie eine zusätzliche Seite oder 4 ^^).

Deine Antwort

3   die antwort
1

Jedes Terminal hat eine Konfiguration ("Getränke") und kann mehrere Untermenüs ("heiß", "kalt") haben, die alle bis zu 24 Elemente enthalten (die "ID" usw.).

Aber der JSON, den Sie als Beispiel gepostet haben, scheint eine andere Struktur zu haben, was Ihre Aufgabe meiner Meinung nach unnötig erschwert. Wenn der JSON-Code eher hierarchisch gruppiert werden würde, wie Sie es in Ihrem Kommentar beschrieben haben, wäre Ihre Aufgabe wirklich einfach. Es hört sich so an, als ob Sie die Möglichkeit haben, den generierten JSON zu ändern. Daher empfehle ich Ihnen, die Hierarchie neu zu gestalten, anstatt zu versuchen, schwer zu verstehenden / zu pflegenden Code zu schreiben, der sich mit einer Datenstruktur befasst, die anfangs nicht ideal war .

Als Beispiel sagen Sie, ein Terminal impliziert seine Konfiguration und seine Menüs, also würde ich die Terminals anstelle der Konfigurationen auf die oberste Ebene setzen, dh, Konfiguration und Menüs werden zu Mitgliedern des Terminals, anstatt umgekehrt. Auf diese Weise können Sie einfach über alle Terminals iterieren und auf deren Menüs, IDs usw. zugreifen, ohne dass Sie wissen müssen, dass dieses spezielle Terminal beispielsweise "Getränke" anbietet.

Ja, ich werde es verwenden, wie Sie sagten, nur mehrere Konfigurationen (einmal definiert) und dann nur die Terminals verbinden, das erspart mir das Erstellen unmöglicher großer Json's ^^ DanFritz
Danke, ja, meine erste Struktur war so, aber es ist auch möglich (wahrscheinlich), dass 5 Terminals alle die gleiche Konfiguration haben. Dies bedeutet, dass ich 5-mal die gleichen Informationen an meinen Server sende, da ich versuche, "eine Konfiguration" für mehrere Temrinals zu speichern, bin ich zu dieser komplexen Struktur gelangt. DanFritz
OK. Um Duplikate zu vermeiden, können Sie Referenzen verwenden. Sie würden die Daten weiterhin in der zweckmäßigeren Hierarchie gruppieren, aber anstatt die Daten explizit zu duplizieren, würden Sie einen Schlüssel "ref" verwenden, der auf eine ID verweist. Dann deklarieren Sie ein Terminal außerhalb der Hierarchie. So würde es einmal deklariert, aber mehrfach referenziert - denken Sie an Fremdschlüssel in einer DB. emboss
3

um eine tiefe Suche in einem Hash durchzuführen, aber zuerst ist etwas mit Ihrem JSON nicht in Ordnung. Ich fürchte, wenn Sie es analysieren, werden Sie feststellen, dass z. B. Terminals nicht alle Schlüssel anzeigen. Der Code muss noch angepasst werden, um ein Array oder einen Hash selbst zurückzugeben.

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

Hier der Code

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

gibt

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

und

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

gibt

<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>
Ja, danke. DanFritz
Vielen Dank, ich habe den JSON geändert, so dass die Terminals jetzt ein Array von IDs sind. Ob das funktioniert? DanFritz
1

einen Hash zu haben, aber dann nicht an den Schlüsseln interessiert zu sein, aber wen soll ich beurteilen, vielleicht bekommen Sie diese seltsamen Daten von irgendwo anders oder so.

In Anbetracht des vereinfachten obigen Beispiels können Sie Folgendes tun:

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

Schauen wir uns nun das kompliziertere Beispiel an:

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

Dies gibt die IDs zurück, ist jedoch hässlich und verliert alle Informationen, von denen die ID stammt. Ohne mehr von Ihrem Code zu sehen, weiß ich nicht, ob das ausreicht oder nicht (es ist wahrscheinlich nicht).

Danke, ist es auch möglich, nicht alle Informationen zu verlieren, von denen die ID stammt, wie Sie sagten? Es ist mehr, dass ich über den obigen Hash iterieren muss. Auch dieser Hash ist aus einem komplexen Formular in jQuery selbst erstellt. Kurz: Es gibt Artikel, Terminals und Konfigurationen. Jedes Terminal verfügt über eine Konfiguration ("Getränke") und kann mehrere Untermenüs ("Heiß", "Kalt") mit bis zu 24 Elementen ("ID" usw.) enthalten. Deshalb ist es so kompliziert ^^ DanFritz
Wenn der Hash selbst erstellt wurde, liegt es an Ihnen, ihn zu vereinfachen (siehe Antwort von @emboss zum Beispiel) ;-) Michael Kohl

Verwandte Fragen