Array associativi multidimensionali in JavaScript


85

Sono presenti i seguenti risultati della query: (key1 e key2 potrebbero essere qualsiasi testo)

id   key1     key2     value

1    fred     apple    2
2    mary     orange   10
3    fred     banana   7
4    fred     orange   4
5    sarah    melon    5
...

e desidero memorizzare i dati in una griglia (forse come un array) ripetendo tutti i record in questo modo:

         apple    orange   banana  melon
fred        2        4         7     -
mary        -        10        -     -
sarah       -        -         -     5

In PHP questo sarebbe davvero semplice, utilizzando array associativi:

$result['fred']['apple'] = 2;

Ma in JavaScript gli array associativi come questo non funzionano. Dopo aver letto tonnellate di tutorial, tutto ciò che ho potuto ottenere è stato questo:

arr=[];
arr[1]['apple'] = 2;

ma arr['fred']['apple'] = 2;non funziona. Ho provato array di oggetti, ma le proprietà degli oggetti non possono essere testo libero. Più leggevo tutorial, più mi confondevo ...

Qualsiasi idea è benvenuta :)


Grazie per le risposte, ma sto scorrendo i risultati della query e desidero impostare i valori uno alla volta. Le righe di esempio (prese come esempio Matt) var grid = {};grid['aa']['bb'] = 1;restituiscono "Uncaught TypeError: Cannot set property 'bb' of undefined". Potrei sbagliarmi, ma con la maggior parte dei tuoi esempi devo conoscere i dati al momento dell'inizializzazione.
Omiod

Ho appena scoperto che var grid = {}; grid['aa'] = {}; grid['aa']['bb'] = 1;funziona. Un test più complesso fallisce, ma sembra che io sia sulla strada giusta
Omiod

2
devi prima inizializzare il sottooggetto, come ho detto nella mia risposta. var grid = {}; grd ['aa'] = {}; quindi puoi fare grid ['aa'] ['bb'] = 1. Ci sono molti modi per verificare se il sottooggetto è già inizializzato (come menzionato nella mia risposta), quindi non sovrascrivi un esistente oggetto.
Matt

aggiornato la mia risposta con del codice aggiuntivo. non sono sicuro di quanto siano profondi i tuoi oggetti o di come stai ottenendo i tuoi dati, ma si spera che ti indirizzerà nella giusta direzione
Matt

Risposte:


155

Basta usare un normale oggetto JavaScript, che "leggere" allo stesso modo dei tuoi array associativi. Devi ricordarti di inizializzarli anche prima.

var obj = {};

obj['fred'] = {};
if('fred' in obj ){ } // can check for the presence of 'fred'
if(obj.fred) { } // also checks for presence of 'fred'
if(obj['fred']) { } // also checks for presence of 'fred'

// The following statements would all work
obj['fred']['apples'] = 1;
obj.fred.apples = 1;
obj['fred'].apples = 1;

// or build or initialize the structure outright
var obj = { fred: { apples: 1, oranges: 2 }, alice: { lemons: 1 } };

Se stai esaminando i valori, potresti avere qualcosa che assomiglia a questo:

var people = ['fred', 'alice'];
var fruit = ['apples', 'lemons'];

var grid = {};
for(var i = 0; i < people.length; i++){
    var name = people[i];
    if(name in grid == false){
        grid[name] = {}; // must initialize the sub-object, otherwise will get 'undefined' errors
    }

    for(var j = 0; j < fruit.length; j++){
        var fruitName = fruit[j];
        grid[name][fruitName] = 0;
    }
}

È riuscito a utilizzare l'esempio sul codice di produzione (un'estensione di Chrome) e funziona bene. Grazie. Finalmente sto imparando a gestire gli oggetti in JS!
Omiod

3
Non posso votare abbastanza bene questa risposta! La parte che causava il ritorno continuo del mio oggetto indefinito era che NON stavo inizializzando il sottooggetto. Quindi assicurati di farlo! esempio: grid[name] = {};
Jason Pudzianowski

1
@ Matt Esiste un modo per ottenere obj.fred.apples utilizzando un solo set di []? Suppongo di no. obj["fred.apples"]per esempio
B3RV

E se non conosciamo il numero di array, ad esempio il tuo codice [javasript] var people = ['fred', 'alice']; var fruit = ["mele", "limoni"]; var color = ['red', 'blue'] var ..... -> il numero di array è sconosciuto [/ javascript]
YukiSakura

Posso accedere al primo elemento in obj (fred) per indice numerico? Come obj [0] che si traduce in mele: 1, arance: 2. Posso accedere all'ultimo elemento (che è Alice e risultati in limoni: 1)? ''
Timo

26

Se non deve essere un array, puoi creare un oggetto JS "multidimensionale" ...

<script type="text/javascript">
var myObj = { 
    fred: { apples: 2, oranges: 4, bananas: 7, melons: 0 }, 
    mary: { apples: 0, oranges: 10, bananas: 0, melons: 0 }, 
    sarah: { apples: 0, oranges: 0, bananas: 0, melons: 5 } 
}

document.write( myObject[ 'fred' ][ 'apples' ] );
</script>

JSON è in realtà il formato "stringa" dell'oggetto JavaScript. Quello che hai non è JSON, solo un oggetto JavaScript.
Matt il

Grazie, Matt. Aggiornato il post.
charliegriefer

1
@charliegriefer, la riga document.write non dovrebbe essere: "document.write (myObj ......"
john

13

Javascript è flessibile:

var arr = {
  "fred": {"apple": 2, "orange": 4},
  "mary": {}
  //etc, etc
};

alert(arr.fred.orange);
alert(arr["fred"]["orange"]);
for (key in arr.fred)
    alert(key + ": " + arr.fred[key]);

8
Direi che il nome della variabile "arr" è un termine improprio qui, perché in realtà non è un array, ma un oggetto.
Matt il

Sono un cane pigro e quindi non posso usare la tua soluzione. Se fossi stato impaziente, avrei trovato la mia strada con il tuo esempio di subarray;) Comunque, grazie per il tuo impegno.
Timo

9

Poiché avevo bisogno di ottenere tutti gli elementi in un modo carino, ho incontrato questo soggetto SO "Attraversamento di array / oggetti associativi bidimensionali" - non importa il nome per me, perché la funzionalità conta.

var imgs_pl = { 
    'offer':        { 'img': 'wer-handwritter_03.png', 'left': 1, 'top': 2 },
    'portfolio':    { 'img': 'wer-handwritter_10.png', 'left': 1, 'top': 2 },
    'special':      { 'img': 'wer-handwritter_15.png', 'left': 1, 'top': 2 }
};
for (key in imgs_pl) { 
    console.log(key);
    for (subkey in imgs_pl[key]) { 
        console.log(imgs_pl[key][subkey]);
    }
}

Dovrebbe essere accettata la risposta perché un ciclo è solitamente la strada da percorrere.
Timo

6

Sembra che per alcune applicazioni ci sia un approccio molto più semplice agli array associativi multidimensionali in javascript.

  1. Dato che la rappresentazione interna di tutti gli array sono in realtà come oggetti di oggetti, è stato dimostrato che il tempo di accesso per elementi indicizzati numericamente è in realtà lo stesso degli elementi indicizzati associativi (testo).

  2. il tempo di accesso per gli elementi indicizzati associativi di primo livello non aumenta all'aumentare del numero degli elementi effettivi.

Detto questo, potrebbero esserci molti casi in cui è effettivamente meglio utilizzare un approccio di stringa concatenato per creare l'equivalenza di elementi multidimensionali. Per esempio:

store['fruit']['apples']['granny']['price] = 10
store['cereal']['natural']['oats']['quack'] = 20

va a:

store['fruit.apples.granny.price'] = 10
store['cereal.natural.oats.quack'] = 20

I vantaggi includono:

  • non c'è bisogno di inizializzare sotto-oggetti o capire come combinare al meglio gli oggetti
  • tempo di accesso a un livello. gli oggetti all'interno di oggetti richiedono N volte il tempo di accesso
  • può utilizzare Object.keys () per estrarre tutte le informazioni sulle dimensioni e ..
  • puoi usare la funzione regex.test (stringa) e la funzione array.map sui tasti per estrarre esattamente quello che vuoi.
  • nessuna gerarchia nelle dimensioni.
  • il "punto" è arbitrario - l'uso del carattere di sottolineatura rende effettivamente più semplice la regex
  • ci sono molti script per "appiattire" JSON dentro e fuori da questo formato
  • può usare tutte le altre belle funzioni di elaborazione di array su keylist

3

Ottieni il valore per un array di proprietà di array associativi quando il nome della proprietà è un numero intero:

A partire da un array associativo in cui i nomi delle proprietà sono numeri interi:

var categories = [
    {"1":"Category 1"},
    {"2":"Category 2"},
    {"3":"Category 3"},
    {"4":"Category 4"}
];

Invia elementi all'array:

categories.push({"2300": "Category 2300"});
categories.push({"2301": "Category 2301"});

Passa attraverso l'array e fai qualcosa con il valore della proprietà.

for (var i = 0; i < categories.length; i++) {
    for (var categoryid in categories[i]) {
        var category = categories[i][categoryid];
        // log progress to the console
        console.log(categoryid + " : " + category);
        //  ... do something
    }
}

L'output della console dovrebbe essere simile a questo:

1 : Category 1
2 : Category 2
3 : Category 3
4 : Category 4
2300 : Category 2300
2301 : Category 2301

Come puoi vedere, puoi aggirare la limitazione degli array associativi e fare in modo che il nome di una proprietà sia un numero intero.

NOTA: l'array associativo nel mio esempio è il json che avresti se serializzassi un oggetto Dictionary [].


3

Non usare un array, usa un oggetto.

var foo = new Object();

2
non utilizzare a new Object(), poiché Object.prototype potrebbe avere delle stranezze ad esso associate; usa l'oggetto letterale:var foo = {};
Michael Paulukonis

1
@Michael, pensavo che {} fosse solo zucchero sintattico per new Object (); Molto simile a [] è l'abbreviazione di new Array ()
Matt

1
dalla mia console Chrome JS, entrambi questi constrcuts sembrano identici, compresi i loro prototipi. Anche l'aggiunta di Object.prototype.foo = function () {} appare in entrambi.
Matt

1
@ Matt Penso di essermi sbagliato, stavo mescolando con il new Array()che dovrebbe essere evitato. ugh.
Michael Paulukonis

1
@Michael perché dovrebbe essere evitato il nuovo Array ()?
Matt

2

Non è necessario utilizzare necessariamente gli Oggetti, puoi farlo con normali Array multidimensionali.

Questa è la mia soluzione senza oggetti :

// Javascript
const matrix = [];

matrix.key1 = [
  'value1',
  'value2',
];

matrix.key2 = [
  'value3',
];

che in PHP è equivalente a:

// PHP
$matrix = [
    "key1" => [
        'value1',
        'value2',
    ],
    "key2" => [
        'value3',
    ]
];

1
Come si esegue il loop (si usa ciascuno) in seguito?
Sagive SEO

0

<script language="javascript">

// Set values to variable
var sectionName = "TestSection";
var fileMap = "fileMapData";
var fileId = "foobar";
var fileValue= "foobar.png";
var fileId2 = "barfoo";
var fileValue2= "barfoo.jpg";

// Create top-level image object
var images = {};

// Create second-level object in images object with
// the name of sectionName value
images[sectionName] = {};

// Create a third level object
var fileMapObj = {};

// Add the third level object to the second level object
images[sectionName][fileMap] = fileMapObj;

// Add forth level associate array key and value data
images[sectionName][fileMap][fileId] = fileValue;
images[sectionName][fileMap][fileId2] = fileValue2;


// All variables
alert ("Example 1 Value: " + images[sectionName][fileMap][fileId]);

// All keys with dots
alert ("Example 2 Value: " + images.TestSection.fileMapData.foobar);

// Mixed with a different final key
alert ("Example 3 Value: " + images[sectionName]['fileMapData'][fileId2]);

// Mixed brackets and dots...
alert ("Example 4 Value: " + images[sectionName]['fileMapData'].barfoo);

// This will FAIL! variable names must be in brackets!
alert ("Example 5 Value: " + images[sectionName]['fileMapData'].fileId2);
// Produces: "Example 5 Value: undefined".

// This will NOT work either. Values must be quoted in brackets.
alert ("Example 6 Value: " + images[sectionName][fileMapData].barfoo);
// Throws and exception and stops execution with error: fileMapData is not defined

// We never get here because of the uncaught exception above...
alert ("The End!");
</script>


0
    var myObj = [];
    myObj['Base'] = [];
    myObj['Base']['Base.panel.panel_base'] = {ContextParent:'',ClassParent:'',NameParent:'',Context:'Base',Class:'panel',Name:'panel_base',Visible:'',ValueIst:'',ValueSoll:'',
                                              Align:'',  AlignFrom:'',AlignTo:'',Content:'',onClick:'',Style:'',content_ger_sie:'',content_ger_du:'',content_eng:'' };
    myObj['Base']['Base.panel.panel_top']  = {ContextParent:'',ClassParent:'',NameParent:'',Context:'Base',Class:'panel',Name:'panel_base',Visible:'',ValueIst:'',ValueSoll:'',
                                              Align:'',AlignFrom:'',AlignTo:'',Content:'',onClick:'',Style:'',content_ger_sie:'',content_ger_du:'',content_eng:'' };

    myObj['SC1'] = [];
    myObj['SC1']['Base.panel.panel_base'] = {ContextParent:'',ClassParent:'',NameParent:'',Context:'Base',Class:'panel',Name:'panel_base',Visible:'',ValueIst:'',ValueSoll:'',
                                              Align:'',  AlignFrom:'',AlignTo:'',Content:'',onClick:'',Style:'',content_ger_sie:'',content_ger_du:'',content_eng:'' };
    myObj['SC1']['Base.panel.panel_top']  = {ContextParent:'',ClassParent:'',NameParent:'',Context:'Base',Class:'panel',Name:'panel_base',Visible:'',ValueIst:'',ValueSoll:'',
                                              Align:'',AlignFrom:'',AlignTo:'',Content:'',onClick:'',Style:'',content_ger_sie:'',content_ger_du:'',content_eng:'' };


    console.log(myObj);

    if ('Base' in myObj) {
      console.log('Base found');

      if ('Base.panel.panel_base' in myObj['Base'])  {
        console.log('Base.panel.panel_base found'); 


      console.log('old value: ' + myObj['Base']['Base.panel.panel_base'].Context);  
      myObj['Base']['Base.panel.panel_base'] = 'new Value';
      console.log('new value: ' + myObj['Base']['Base.panel.panel_base']);
      }
    }

Produzione:

  • Base trovata
  • Base.panel.panel_base trovato
  • vecchio valore: Base
  • nuovo valore: nuovo valore

L'operazione di matrice funziona. Non c'è problema.

Iterazione:

     Object.keys(myObj['Base']).forEach(function(key, index) {            
        var value = objcons['Base'][key];                   
      }, myObj);

2
Benvenuto in stackoverflow. Modifica la tua risposta e spiega perché gli snippet di codice risolvono il problema. Maggiori informazioni qui: Come rispondere
Djensen
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.