Visualizzazione dei risultati da 1 a 7 su 7
  1. #1
    Utente di HTML.it
    Registrato dal
    Sep 2012
    Messaggi
    442

    Come "navigare" in una struttura dati tipo hash

    Ciao a tutti, sto facendo un esercizio ma non ne vengo a capo, principalmente perché non ho capito bene come iterare in una struttura dati tipo hash per selezionare solo alcuni elementi.
    Vi mostro il codice che non va:

    codice:
    const json = `{"giorno": "2018-05-15","menu": {"primi": [{"nome": "Tagliatelle al ragù","ingr": 
    ["pasta all'uovo", "manzo", "salsa pomodoro", "spezie"]}, {"nome": "Pasta al pomodoro","ingr": 
    ["pasta secca", "salsa pomodoro", "spezie"]}],"secondi": [{"nome": "Scaloppina ai funghi", "ingr": 
    ["manzo", "funghi secchi", "besciamella"]}, {"nome": "Stracchino e grissini","ingr": ["formaggio fresco", 
    "grissini"]}], "dessert": [{"nome": "fiordilatte","ingr": ["latte", "zucchero", "aromi naturali"]}, 
    {"nome": "Kiwi", "ingredienti": ["kiwi"]}]}}`;
    
    const myMenu = JSON.parse(json);
    
    mostraMenu(myMenu);
    
    function mostraMenu(menu) {
      
      for (var i in menu) { //cioè 'primo', 'secondo', 'dessert'
        var html="";
        html += "<div class='menu'><h2>"+i+"</h2><select>";
        for (var j=0; j<menu[i].length; j++) { 
          html += "<option>"+menu[i][j].nome;
          html += "(" + menu[i][j].ingr.join(', ') + ")"; --->> ERRORE SU QUESTA
          html += "</option>";
        }
        html += "</select>";
      }
      html += "</div><button onclick=‘spedisciMenu()'>Spedisci</button>";
      document.getElementById("formMenu").innerHTML=html;
    }
    L'errore che ottengo sulla riga evidenziata è: Uncaught TypeError: menu[i][j].ingr is undefined.
    Presumo ci sia qualcosa che non va nel secondo ciclo for.
    Sostanzialmente io passo un oggetto JSON che è praticamente un menu, dove ogni menu è legato al giorno (ogni giorno c'è un menu diverso), in ogni menu ci sono 3 campi: primo, secondo, dessert. Che a loro volta contengono l'elenco delle pietanze proposte (ed ognuna ha un nome ed una lista ingredienti).
    Scopo dell'esercizio è: per ogni categoria (primo, secondo, dessert): visualizza un menu a tendina con un elemento per ogni cibo. Di ogni cibo viene mostrato il nome e tra parentesi gli ingredienti.
    Grazie a chiunque vorrà aiutarmi.

  2. #2
    Utente di HTML.it
    Registrato dal
    Sep 2012
    Messaggi
    442
    Nel frattempo mi sono resa conto di una parte dell'errore, ma ancora non arrivo a capo della soluzione definitiva.
    Ecco il nuovo codice (riporto solo la funzione):
    codice:
    function mostraMenu(menu) {
      var html="";
      for (var i in menu.menu) { 
        html += "<div class='menu'><h2>"+i+"</h2><select>";
        for (var j=0; j<menu.menu[i].length; j++) {
          html += "<option>"+ menu.menu[i][j].nome;
          html += "</option>";
        }
        html += "</select>";
      }
      html += "</div><button onclick=‘spedisciMenu()'>Spedisci</button>";
      document.getElementById("formMenu").innerHTML=html;
    }
    Ora fa quasi tutto quello che dovrebbe, ma non so come fare per accedere all'array degli ingredienti, qualunque cosa io stia provando non funziona. In pratica a fianco al nome del piatto (che ora viene mostrato correttamente nel menu a tendina) dovrei mostrare anche la lista degli ingredienti.
    In sostanza, quello che sto cercando di capire, è come ispezionare una struttura dati composta da oggetti che contegono oggetti ed array annidati.

  3. #3
    Utente di HTML.it
    Registrato dal
    Sep 2012
    Messaggi
    442
    Per renderlo visivamente più chiaro, questo è il file JSON su cui sto lavorando:

    codice:
    {
      "giorno": "2018-05-15",
      "menu": {
        "primi": [{
          "nome": "Tagliatelle al ragù",
          "ingr": ["pasta all'uovo", "manzo", "salsa pomodoro", "spezie"]
        }, {
          "nome": "Pasta al pomodoro",
          "ingr": ["pasta secca", "salsa pomodoro", "spezie"]
        }],
        "secondi": [{
          "nome": "Scaloppina ai funghi",
          "ingr": ["manzo", "funghi secchi", "besciamella"]
        }, {
          "nome": "Stracchino e grissini",
          "ingr": ["formaggio fresco", "grissini"]
        }],
        "dessert": [{
          "nome": "fiordilatte",
          "ingr": ["latte", "zucchero", "aromi naturali"]
        }, {
          "nome": "Kiwi",
          "ingredienti": ["kiwi"]
        }]
      }
    }
    Quel che vorrei sapere è quindi come accedere all'elenco degli ingredienti per ogni tipo di piatto.

  4. #4
    Moderatore di CSS L'avatar di KillerWorm
    Registrato dal
    Apr 2004
    Messaggi
    5,771
    Ciao, premetto: in questi casi consiglio di eseguire un monitoraggio delle eventuali diverse variabili cosi da capire come poter intervenire per accedere a quei particolari dati. Puoi quindi usare qualche console.log() posizionato nei punti strategici, ad esempio dentro il ciclo, quindi verificare cosa salta fuori nella console del tuo browser (F12 per aprirla).

    Detto ciò, per iterare/manipolare array ed oggetti,esistono diverse istruzioni (come i cicli) nonché dei metodi specifici. Conoscendo a priori la struttura dei dati puoi quindi usare degli appositi metodi per iterare/manipolare o gli elementi di un array o le proprietà di un oggetto.

    Nel tuo caso hai già raggiunto il "nome" del piatto che di fatto è una stringa, quindi puoi concatenarla direttamente nella stringa html di output.

    Analogamente puoi accedere alla proprietà "ingr" che in questo caso è un array.

    codice:
    function mostraMenu(menu) {
      var html="";
      for (var i in menu.menu) { 
        html += "<div class='menu'><h2>"+i+"</h2><select>";
        for (var j=0; j<menu.menu[i].length; j++) {
        
    console.log( menu.menu[i][j].nome ); // Qui stai accedendo alla proprietà "nome" che restituisce una stringa
    console.log( menu.menu[i][j].ingr ); // Qui accedi alla proprietà "ingr" che restituisce un array
    
          html += "<option>"+ menu.menu[i][j].nome;
          html += "</option>";
        }
        html += "</select>";
      }
      html += "</div><button onclick=‘spedisciMenu()'>Spedisci</button>";
      document.getElementById("formMenu").innerHTML=html;
    }
    Ora, se l'intento è quello di ottenere una semplice stringa di tutte le voci di tale array, non hai bisogno di iterarle ma puoi usare il metodo join() che restituisce appunto una stringa concatenando le voci.

    Non ti indico direttamente la soluzione, dato che è un esercizio, ma ti invito a consultare la documentazione e fare qualche prova.

    Fai sapere, se poi hai bisogno di ulteriore aiuto chiedi pure


    PS: fai attenzione, per l'ultimo piatto ("Kiwi") hai usato la proprietà "ingredienti" mentre per tutti gli altri piatti hai usato "ingr". Presumo sia una tua svista, è chiaro però che una struttura dati inconsistente potrebbe darti problemi.
    Installa Forum HTML.it Toolset per una fruizione ottimale del Forum

  5. #5
    Utente di HTML.it
    Registrato dal
    Sep 2012
    Messaggi
    442
    Ciao, intanto grazie mille per la risposta. Nel frattempo però sono arrivata da sola alla soluzione, che ti posto per un confronto:

    codice:
    function mostraMenu(menu) {
      var html="";
      for (var i in menu.menu) { 
        html += "<div class='menu'><h2>"+i+"</h2><select>";
        for (var j=0; j<menu.menu[i].length; j++) {
          html += "<option>"+ menu.menu[i][j].nome + " ";
            html += "(";
            for (var m in menu.menu[i][j].ingr) {
            if (menu.menu[i][j].ingr.indexOf(menu.menu[i][j].ingr[m]) == menu.menu[i][j].ingr.length-1)
              html += menu.menu[i][j].ingr[m];
            else
              html += menu.menu[i][j].ingr[m] + ", ";
          }
          html += ")";
          html += "</option>";
        }
        html += "</select>";
      }
      html += "</div><button onclick='spedisciMenu()'>Spedisci </button>";
      document.getElementById("formMenu").innerHTML=html;
    }
    L'if...else l'ho messo per controllare che l'elemento della lista di ingredienti sia o meno l'ultimo, in modo da non mostrare la virgola anche alla fine della lista ingredienti. Non so se ci sia un modo più elegante per farlo, ma questo funziona.
    Ho provato ad usare il join() come del resto era stato fatto nella soluzione proposta (non funzionante), ma mi dava errore, per cui alla fine sono arrivata ad iterare anche nella lista ingredienti.
    Alla fine sono arrivata alla soluzione facendo prove su prove, aiutandomi anche come hai detto tu con gli input sulla console, però se devo dire che ho capito benissimo quel che ho fatto, mentirei. Del resto ho iniziato a vedere JS da poco e lo conosco davvero superficialmente.
    Sì, nel frattempo mi ero anche accorta di quella svista nella struttura dati
    Comunque, come si potrebbe migliorare la mia soluzione? Vorrei arrivare a capire bene come "muovermi" in strutture dati "complesse" come questa.
    Grazie ancora.

  6. #6
    Utente di HTML.it
    Registrato dal
    Sep 2012
    Messaggi
    442
    Bene, mi sono complicata la vita inutilmente (come al solito!), la soluzione era molto più semplice di quanto immaginassi e se avessi avuto più conoscenza di JS e delle strutture dati ci sarei arrivata subito. Eccola qui:

    codice:
    function mostraMenu(menu) {
      var html="";
      for (var i in menu.menu) { 
        html += "<div class='menu'><h2>"+i+"</h2><select>";
        for (var j=0; j<menu.menu[i].length; j++) {
          html += "<option>"+ menu.menu[i][j].nome + " ";
          html += "(" + menu.menu[i][j].ingr.join(', ') + ")";
          html += "</option>";
        }
        html += "</select>";
      }
      html += "</div><button onclick='spedisciMenu()'>Spedisci </button>";
      document.getElementById("formMenu").innerHTML=html;
    }
    Tutto il problema stava in quel .menu mancante

  7. #7
    Moderatore di CSS L'avatar di KillerWorm
    Registrato dal
    Apr 2004
    Messaggi
    5,771
    Bene, mi sono complicata la vita inutilmente (come al solito!), la soluzione era molto più semplice di quanto immaginassi
    capita a tutti, molte volte anche hai più bravi. Il tutto sta nel non arrendersi e nella continua pratica, vedo infatti che sei riuscita in qualche modo nell'intento.

    Noto comunque un'ulteriore svista nel tuo ultimo script. Nel primo ciclo stai aprendo il <div class='menu'>, in sostanza uno per ogni select, ma hai messo la chiusura solo una volta dopo il ciclo stesso. E' chiaro che risulterà un html malformato. Se vuoi che il div sia unico e che avvolga tutti i select, dovrai metterne l'apertura all'inizio, prima del ciclo stesso; se invece intendi creare più div, uno per ogni select, dovrai metterne la chiusura prima che sia concluso il primo ciclo.

    Comunque, come si potrebbe migliorare la mia soluzione? Vorrei arrivare a capire bene come "muovermi" in strutture dati "complesse" come questa.
    Se la struttura è conosciuta a priori, come nel tuo caso, in generale può andare bene il procedimento da te usato, cioè accedendo alle proprietà degli oggetti in modo diretto e iterando gli elementi degli array là dove ti serve.

    Diverso sarebbe se si volesse eseguire un parsing di una struttura dove non si conoscono né il tipo di dati né le eventuali proprietà degli oggetti, per cui andrebbero esaminati singolarmente tutti i vari livelli della struttura con delle iterazioni o in modo ricorsivo, analizzando opportunamente tutti i contenuti. Ma questo non è il tuo caso.

    Nel tuo caso la struttura è comunque conosciuta e relativamente semplice. In casi più complessi sì fa uso anche di librerie/framework che semplificano ulteriormente la stesura del codice; non mi sembra comunque il tuo caso.

    Grosso modo la tua soluzione finale può andare bene, non c'è molto da migliorare.
    Installa Forum HTML.it Toolset per una fruizione ottimale del Forum

Permessi di invio

  • Non puoi inserire discussioni
  • Non puoi inserire repliche
  • Non puoi inserire allegati
  • Non puoi modificare i tuoi messaggi
  •  
Powered by vBulletin® Version 4.2.1
Copyright © 2025 vBulletin Solutions, Inc. All rights reserved.