Mehrdimensionale assoziative Arrays in JavaScript

84

Es gibt die folgenden Abfrageergebnisse: (Schlüssel1 und Schlüssel2 können beliebiger Text sein)

id   key1     key2     value

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

und ich möchte die Daten in einem Raster (möglicherweise als Array) speichern, das alle Datensätze wie folgt durchläuft :

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

In PHP wäre dies mit assoziativen Arrays sehr einfach:

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

In JavaScript funktionieren solche assoziativen Arrays jedoch nicht. Nachdem ich Tonnen von Tutorials gelesen hatte, konnte ich nur Folgendes bekommen:

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

arr['fred']['apple'] = 2;funktioniert aber nicht Ich habe Arrays von Objekten ausprobiert, aber Objekteigenschaften können kein Freitext sein. Je mehr ich Tutorials las, desto verwirrter wurde ich ...

Jede Idee ist willkommen :)

Omiod
quelle
Vielen Dank für die Antworten, aber ich durchlaufe die Abfrageergebnisse und möchte die Werte einzeln festlegen. Die Beispielzeilen (aus dem Matt-Beispiel) geben var grid = {};grid['aa']['bb'] = 1;"Uncaught TypeError: Eigenschaft 'bb' von undefined kann nicht festgelegt werden" zurück. Ich könnte mich irren, aber bei den meisten Ihrer Beispiele muss ich die Daten zum Zeitpunkt der Initialisierung kennen.
Omiod
Ich habe gerade festgestellt, dass das var grid = {}; grid['aa'] = {}; grid['aa']['bb'] = 1;funktioniert. Ein komplexerer Test schlägt fehl, aber es sieht so aus, als wäre ich auf dem richtigen Weg
Omiod
2
Sie müssen zuerst das Unterobjekt initialisieren, wie ich in meiner Antwort erwähnt habe. var grid = {}; grd ['aa'] = {}; Dann können Sie grid ['aa'] ['bb'] = 1 ausführen. Es gibt viele Möglichkeiten, um zu überprüfen, ob das Unterobjekt bereits initialisiert ist (wie in meiner Antwort erwähnt), damit Sie ein vorhandenes nicht überschreiben Objekt.
Matt
hat meine Antwort mit einem zusätzlichen Code aktualisiert. Ich bin mir nicht sicher, wie tief Ihre Objekte sind oder wie Sie Ihre Daten erhalten, aber ich werde Sie hoffentlich in die richtige Richtung weisen
Matt

Antworten:

152

Verwenden Sie einfach ein reguläres JavaScript-Objekt, das genauso wie Ihre assoziativen Arrays "liest". Sie müssen daran denken, sie auch zuerst zu initialisieren.

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

Wenn Sie über Werte schauen, haben Sie möglicherweise etwas, das so aussieht:

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;
    }
}
Matt
quelle
Es ist gelungen, das Beispiel für Produktionscode (eine Chrome-Erweiterung) zu verwenden, und es funktioniert einwandfrei. Vielen Dank. Endlich bekomme ich, wie man mit Objekten in JS umgeht!
Omiod
3
Ich kann diese Antwort nicht genug bewerten! Der Teil, der dazu führte, dass mein Objekt ständig undefiniert zurückgab, war, dass ich das Unterobjekt NICHT initialisierte. Stellen Sie also sicher, dass Sie dies tun! Beispiel: grid[name] = {};
Jason Pudzianowski
1
@Matt Gibt es eine Möglichkeit, obj.fred.apples mit nur einem Satz von [] abzurufen? Ich gehe nicht davon aus. obj["fred.apples"]zum Beispiel
theB3RV
Was ist, wenn wir die Anzahl der Arrays nicht kennen, zum Beispiel Ihren Code [javasript] var people = ['fred', 'alice']; varruit = ['Äpfel', 'Zitronen']; var color = ['rot', 'blau'] var ..... -> die Anzahl der Arrays ist unbekannt [/ javascript]
YukiSakura
Kann ich über einen numerischen Index auf das erste Element in obj (fred) zugreifen? Wie obj [0], was zu Äpfeln führt: 1, Orangen: 2. Kann ich auf den letzten Gegenstand zugreifen (der Alice ist und Zitronen ergibt: 1)? `
Timo
25

Wenn es nicht hat , ein Array sein, können Sie ein „mehrdimensionale“ JS - Objekt erstellen ...

<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>
charliegriefer
quelle
JSON ist eigentlich das 'stringifizierte' Format des JavaScript-Objekts. Was Sie dort haben, ist nicht JSON, sondern nur ein JavaScript-Objekt.
Matt
Danke, Matt. Der Beitrag wurde aktualisiert.
Charliegriefer
1
@ charliegriefer, sollte die Zeile document.write nicht lauten: "document.write (myObj ......"
John
13

Javascript ist flexibel:

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]);
Cambraca
quelle
8
Ich würde sagen, der Variablenname 'arr' ist hier eine Fehlbezeichnung, da es sich eigentlich nicht um ein Array, sondern um ein Objekt handelt.
Matt
Ich bin ein fauler Hund und kann daher Ihre Lösung nicht verwenden. Wenn ich eifrig gewesen wäre, würde ich mich mit Ihrem Subarray-Beispiel zurechtfinden;) Wie auch immer, danke für Ihre Bemühungen.
Timo
9

Da ich alle Elemente auf eine nette Art und Weise erhalten musste, stieß ich auf dieses SO-Subjekt "Durchqueren eines zweidimensionalen assoziativen Arrays / Objekts" - unabhängig vom Namen für mich, da die Funktionalität zählt.

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]);
    }
}
Michal - wereda-net
quelle
Sollte als Antwort akzeptiert werden, da normalerweise eine Schleife der richtige Weg ist.
Timo
5

Es scheint, dass es für einige Anwendungen einen weitaus einfacheren Ansatz für mehrdimensionale assoziative Arrays in Javascript gibt.

  1. Da die interne Darstellung aller Arrays tatsächlich Objekte von Objekten sind, wurde gezeigt, dass die Zugriffszeit für numerisch indizierte Elemente tatsächlich dieselbe ist wie für assoziative (Text) indizierte Elemente.

  2. Die Zugriffszeit für assoziative indizierte Elemente der ersten Ebene steigt nicht an, wenn die Anzahl der tatsächlichen Elemente zunimmt.

In Anbetracht dessen kann es viele Fälle geben, in denen es tatsächlich besser ist, einen verketteten Zeichenfolgenansatz zu verwenden, um die Äquivalenz mehrdimensionaler Elemente zu erstellen. Zum Beispiel:

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

geht zu:

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

Zu den Vorteilen gehören:

  • Sie müssen keine Unterobjekte initialisieren oder herausfinden, wie Objekte am besten kombiniert werden können
  • einstufige Zugriffszeit. Objekte innerhalb von Objekten benötigen die N-fache Zugriffszeit
  • kann Object.keys () verwenden, um alle Dimensionsinformationen zu extrahieren und ..
  • Mit der Funktion regex.test (Zeichenfolge) und der Funktion array.map auf den Tasten können Sie genau das herausziehen, was Sie möchten.
  • Keine Hierarchie in den Dimensionen.
  • Der "Punkt" ist willkürlich - die Verwendung von Unterstrichen erleichtert die Regex
  • Es gibt viele Skripte zum "Reduzieren" von JSON in und aus diesem Format
  • kann alle anderen netten Array-Verarbeitungsfunktionen auf der Keylist verwenden
sdw
quelle
3

Ruft den Wert für die Eigenschaft eines Arrays assoziativer Arrays ab, wenn der Eigenschaftsname eine Ganzzahl ist:

Beginnend mit einem assoziativen Array, bei dem die Eigenschaftsnamen Ganzzahlen sind:

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

Elemente in das Array verschieben:

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

Durchlaufen Sie das Array und machen Sie etwas mit dem Eigenschaftswert.

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

Die Konsolenausgabe sollte folgendermaßen aussehen:

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

Wie Sie sehen können, können Sie die assoziative Array-Einschränkung umgehen und einen Eigenschaftsnamen als Ganzzahl festlegen.

HINWEIS: Das assoziative Array in meinem Beispiel ist das JSON, das Sie hätten, wenn Sie ein Dictionary [] -Objekt serialisiert hätten.

Jason Williams
quelle
3

Verwenden Sie kein Array, sondern ein Objekt.

var foo = new Object();
Tim
quelle
2
Verwenden Sie kein a new Object(), da mit dem Object.prototype möglicherweise eine Verrücktheit verbunden ist. Verwenden Sie das Objektliteral:var foo = {};
Michael Paulukonis
1
@Michael Ich dachte, {} wäre nur syntaktischer Zucker für neues Objekt (); Ähnlich wie [] steht für new Array ()
Matt
1
In meiner Chrome JS-Konsole sind beide Constrcuts identisch, einschließlich ihrer Prototypen. Sogar das Hinzufügen von Object.prototype.foo = function () {} wird in beiden angezeigt.
Matt
1
@Matt Ich glaube, ich liege falsch, ich habe das verwechselt, new Array()was vermieden werden sollte. Pfui.
Michael Paulukonis
1
@ Michael, warum sollte neues Array () vermieden werden?
Matt
2

Sie müssen nicht unbedingt Objekte verwenden, sondern können dies mit normalen mehrdimensionalen Arrays tun.

Dies ist meine Lösung ohne Objekte :

// Javascript
const matrix = [];

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

matrix.key2 = [
  'value3',
];

was in PHP gleichbedeutend ist mit:

// PHP
$matrix = [
    "key1" => [
        'value1',
        'value2',
    ],
    "key2" => [
        'value3',
    ]
];
Francesco Borzi
quelle
1
Wie können Sie dies später wiederholen (jeweils verwenden)?
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>

Rich Schramm
quelle
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']);
      }
    }

Ausgabe:

  • Basis gefunden
  • Base.panel.panel_base gefunden
  • alter Wert: Basis
  • neuer Wert: neuer Wert

Die Array-Operation funktioniert. Es gibt kein Problem.

Wiederholung:

     Object.keys(myObj['Base']).forEach(function(key, index) {            
        var value = objcons['Base'][key];                   
      }, myObj);
Necips
quelle
2
Willkommen bei stackoverflow. Bitte bearbeiten Sie Ihre Antwort und erklären Sie, warum Ihre Codefragmente das Problem lösen. Weitere Infos hier: Wie zu
antworten