Zum Inhalt springen
aviral gupta

// I5.1 · ca. 34 Min. · Aufbau

Map und Set: Daten nach Schlüssel, Werte einmal

Nach dieser Lektion legen Sie Daten mit einer Map unter einem Schlüssel ab und schlagen sie nach, entfernen Duplikate mit einem Set und zählen oder gruppieren eine Liste in wenigen Zeilen.

Lektion 1 von 5 in I5 Mit Daten arbeiten

Anfang des Moduls

Danach können Sie

  • Daten mit Map nach Schlüssel ablegen, lesen und durchlaufen: set, get, has, delete und size
  • Eindeutige Werte mit Set halten und zwischen Arrays, Objekten, Maps und Sets umwandeln
  • Werte mit einer Map zählen und gruppieren, mit dem has/set-Muster oder mit ES2026-getOrInsert
  1. Aufwärmen · Aufgabe 1 von 7

    Zum Aufwärmen aus Lektion B5.3. Was gibt das aus?

    const prices = { tea: 3, cake: 4 };
    console.log(Object.entries(prices));
  2. Vorhersagen · Aufgabe 2 von 7

    Sagen Sie es vorher, bevor Sie weiterlesen. Dieselben zwei Schlüssel gehen in ein Objekt und in eine Map. Was wird ausgegeben, als eine Zeile gelesen?

    const seen = {};
    seen[1] = "number one";
    seen["1"] = "string one";
    console.log(Object.keys(seen).length);
    
    const map = new Map();
    map.set(1, "number one");
    map.set("1", "string one");
    console.log(map.size);
  3. Üben · Aufgabe 3 von 7

    Ergänzen Sie die Collection, die die Duplikate entfernt.

    const unique = [...new ____(["de", "en", "de", "fr"])];
    const unique = [...new(["de", "en", "de", "fr"])];
  4. Üben · Aufgabe 4 von 7

    Ordnen Sie jedem Map-Mitglied zu, was es liefert.

  5. Üben · Aufgabe 5 von 7

    Eine Map zählt die Wörter. Was gibt das aus?

    const words = ["a", "b", "a", "c", "a"];
    const counts = new Map();
    for (const word of words) {
      counts.set(word, (counts.get(word) ?? 0) + 1);
    }
    console.log([...counts]);
  6. Denksport · Aufgabe 6 von 7

    Knobelaufgabe. Die Einstellung wird mit eckigen Klammern gespeichert. Was gibt das aus?

    const settings = new Map();
    settings["theme"] = "dark";
    console.log(settings.size, settings.has("theme"));
  7. Anwenden · Aufgabe 7 von 7

    Kleine Aufgabe: Sie haben words = ["apple", "bread", "avocado", "butter", "cheese"]. Gruppieren Sie sie nach ihrem ersten Buchstaben in einer Map, mit dem has/set-Muster. Durchlaufen Sie dann die Map und geben Sie pro Buchstabe eine Zeile aus, etwa a: apple, avocado, und zum Schluss die Anzahl der Buchstaben.

    Prüfen Sie Ihr Ergebnis anhand dieser Liste

Selbst programmieren

Lesen Sie das ausgearbeitete Beispiel und lösen Sie dann die Übungen. Ihr Code läuft in Ihrem Browser oder auf Ihrem Computer und wird nie hochgeladen.

Ausgearbeitetes Beispiel

Besucher, Seitenaufrufe und Besucher pro Seite

Eine Liste von Website-Besuchen wird zu drei Antworten. Ein Set liefert die Besucher, jeden einmal. Eine Map zählt die Aufrufe pro Seite. Eine zweite Map gruppiert die Besucher nach Seite: pushTo() nutzt ES2026-getOrInsert, wo die Laufzeit es hat, und anderswo das klassische has/set-Muster, gibt also in jeder Laufzeit dasselbe aus. Ein Objekt als Schlüssel zeigt, dass eine Map Schlüssel nach Identität findet, und Object.fromEntries bereitet die Zähler für JSON vor.

main.js

// Visits to a small website: [visitor, page].
const visits = [
  ["ada", "/home"], ["bo", "/blog"], ["ada", "/blog"],
  ["cy", "/home"], ["bo", "/blog"], ["ada", "/home"],
];

// 1. A Set keeps each value once, in the order it first came.
const visitors = new Set(visits.map(([visitor]) => visitor));
console.log("visitors:", visitors.size, [...visitors].join(", "));

// 2. Counting: one Map entry per page.
const views = new Map();
for (const [, page] of visits) {
  views.set(page, (views.get(page) ?? 0) + 1);
}
for (const [page, count] of views) console.log(page, count);

// 3. Grouping: page -> array of visitors.
function pushTo(map, key, value) {
  if (typeof Map.prototype.getOrInsert === "function") {
    map.getOrInsert(key, []).push(value); // ES2026 shortcut
  } else {
    if (!map.has(key)) map.set(key, []); // the classic way
    map.get(key).push(value);
  }
}
const byPage = new Map();
for (const [visitor, page] of visits) pushTo(byPage, page, visitor);
console.log("/blog:", byPage.get("/blog").join(" "));

// 4. Any value can be a key, even an object.
const ada = { name: "Ada" };
const lastSeen = new Map([[ada, "/home"]]);
console.log(lastSeen.get(ada), lastSeen.get({ name: "Ada" }));

// 5. Back to a plain object, for JSON.
console.log(JSON.stringify(Object.fromEntries(views)));

Ausführen mit

node main.js

Ausgabe

visitors: 3 ada, bo, cy
/home 3
/blog 3
/blog: bo ada bo
/home undefined
{"/home":3,"/blog":3}
  • Das Set behielt jeden Besucher einmal, in der Reihenfolge des ersten Besuchs.
  • Die Map listete /home vor /blog, weil /home zuerst gezählt wurde.
  • lastSeen.get({ name: "Ada" }) ist undefined: Ein gleich aussehendes Objekt ist trotzdem ein anderer Schlüssel.
Ändern und ausführen

Tab rückt ein, Umschalt+Tab rückt aus. Um den Editor mit der Tastatur zu verlassen, drücken Sie Esc und dann Tab.

Beim ersten Ausführen lädt Ihr Browser den JavaScript-Runner herunter (bis zu 0.1 MB) und speichert ihn im Cache. Ihr Code läuft in der eigenen Engine Ihres Browsers und bleibt auf Ihrem Gerät.

Übungen

Übung 1 von 2

Die Wörter zählen

countWords(text) soll eine Map von jedem Wort auf seine Häufigkeit zurückgeben, ohne Beachtung der Groß- und Kleinschreibung: countWords("The cat and the hat").get("the") ist 2. Wörter sind durch einzelne Leerzeichen getrennt. Der Startcode setzt jeden Zähler auf 1. Korrigieren Sie ihn so, dass ein erneut gesehenes Wort seinen Zähler um 1 erhöht.

Tab rückt ein, Umschalt+Tab rückt aus. Um den Editor mit der Tastatur zu verlassen, drücken Sie Esc und dann Tab.

Beim ersten Ausführen lädt Ihr Browser den JavaScript-Runner herunter (bis zu 0.1 MB) und speichert ihn im Cache. Ihr Code läuft in der eigenen Engine Ihres Browsers und bleibt auf Ihrem Gerät.

Hinweise
  1. Hinweis 1

    Führen Sie die Tests aus: the wird einmal gezählt. Was tut der Startcode, wenn er ein Wort zum zweiten Mal sieht?

  2. Hinweis 2

    Lesen Sie zuerst den alten Zähler. counts.get(word) ist für ein neues Wort undefined.

  3. Hinweis 3

    counts.set(word, (counts.get(word) ?? 0) + 1);

Eine Lösung zeigen

Ein möglicher Lösungsweg. Ihrer kann anders aussehen und trotzdem alle Prüfungen bestehen.

export function countWords(text) {
  const counts = new Map();
  for (const word of text.toLowerCase().split(" ")) {
    counts.set(word, (counts.get(word) ?? 0) + 1);
  }
  return counts;
}
Auf dem eigenen Computer ausführen

Installieren Sie ECMAScript 2026 oder neuer. Speichern Sie diese Dateien in einem Ordner, öffnen Sie dort ein Terminal und führen Sie die Befehle unten aus.

main.js

export function countWords(text) {
  const counts = new Map();
  for (const word of text.toLowerCase().split(" ")) {
    counts.set(word, 1);
  }
  return counts;
}

main.test.js

import {test} from 'node:test';
import assert from 'node:assert/strict';
import {countWords} from './main.js';

test('countWords gibt eine Map zurück', () => {
  const counts = countWords('a b');
  assert.ok(counts instanceof Map, `countWords gab ${counts} zurück, keine Map`);
});

test('Ein wiederholtes Wort wird jedes Mal gezählt', () => {
  const counts = countWords('the cat and the hat');
  assert.equal(counts.get('the'), 2, `the wurde ${counts.get('the')}-mal gezählt`);
  assert.equal(counts.get('cat'), 1, `cat wurde ${counts.get('cat')}-mal gezählt`);
});

test('Die Schreibweise wird ignoriert, die Reihenfolge ist die des ersten Auftretens', () => {
  const counts = countWords('Go go GO stop');
  assert.deepEqual([...counts], [['go', 3], ['stop', 1]], `die Einträge sind ${JSON.stringify([...counts])}`);
});

package.json

{
  "type": "module"
}

package.json sagt Node.js, dass die .js-Dateien Module sind; lassen Sie die Datei im Ordner.

Programm ausführen:

node main.js

Prüfungen ausführen (learnrun.js muss im selben Ordner liegen):

node --test
learnrun.js herunterladen

Übung 2 von 2

Bestellungen nach Kunde gruppieren

groupOrders(orders) bekommt Objekte wie {id: 7, customer: "ada"} und soll eine Map von jedem Kunden auf das Array seiner Bestell-IDs zurückgeben, in Reihenfolge. Der Startcode legt für jede Bestellung ein neues Array an, sodass jeder Kunde nur die letzte ID behält. Legen Sie das Array nur für einen neuen Kunden an und hängen Sie dann an. Nutzen Sie has und set; verlassen Sie sich nicht auf getOrInsert.

Tab rückt ein, Umschalt+Tab rückt aus. Um den Editor mit der Tastatur zu verlassen, drücken Sie Esc und dann Tab.

Beim ersten Ausführen lädt Ihr Browser den JavaScript-Runner herunter (bis zu 0.1 MB) und speichert ihn im Cache. Ihr Code läuft in der eigenen Engine Ihres Browsers und bleibt auf Ihrem Gerät.

Hinweise
  1. Hinweis 1

    Führen Sie die Tests aus: ada hat nur [4]. Wann läuft byCustomer.set(order.customer, [])?

  2. Hinweis 2

    Legen Sie das leere Array nur an, wenn der Kunde noch nicht in der Map ist: byCustomer.has(order.customer).

  3. Hinweis 3

    if (!byCustomer.has(order.customer)) byCustomer.set(order.customer, []);

Eine Lösung zeigen

Ein möglicher Lösungsweg. Ihrer kann anders aussehen und trotzdem alle Prüfungen bestehen.

export function groupOrders(orders) {
  const byCustomer = new Map();
  for (const order of orders) {
    if (!byCustomer.has(order.customer)) byCustomer.set(order.customer, []);
    byCustomer.get(order.customer).push(order.id);
  }
  return byCustomer;
}
Auf dem eigenen Computer ausführen

Installieren Sie ECMAScript 2026 oder neuer. Speichern Sie diese Dateien in einem Ordner, öffnen Sie dort ein Terminal und führen Sie die Befehle unten aus.

main.js

export function groupOrders(orders) {
  const byCustomer = new Map();
  for (const order of orders) {
    byCustomer.set(order.customer, []);
    byCustomer.get(order.customer).push(order.id);
  }
  return byCustomer;
}

main.test.js

import {test} from 'node:test';
import assert from 'node:assert/strict';
import {groupOrders} from './main.js';

const orders = [
  {id: 1, customer: 'ada'},
  {id: 2, customer: 'bo'},
  {id: 3, customer: 'ada'},
  {id: 4, customer: 'ada'}
];

test('Jeder Kunde behält alle seine Bestell-IDs', () => {
  const groups = groupOrders(orders);
  assert.deepEqual(groups.get('ada'), [1, 3, 4], `ada hat ${JSON.stringify(groups.get('ada'))}`);
  assert.deepEqual(groups.get('bo'), [2], `bo hat ${JSON.stringify(groups.get('bo'))}`);
});

test('Die Kunden kommen in der Reihenfolge ihrer ersten Bestellung', () => {
  const groups = groupOrders(orders);
  assert.deepEqual([...groups.keys()], ['ada', 'bo'], `die Schlüssel sind ${JSON.stringify([...groups.keys()])}`);
});

test('Keine Bestellungen ergeben eine leere Map', () => {
  const groups = groupOrders([]);
  assert.equal(groups.size, 0, `die Map hat ${groups.size} Einträge`);
});

package.json

{
  "type": "module"
}

package.json sagt Node.js, dass die .js-Dateien Module sind; lassen Sie die Datei im Ordner.

Programm ausführen:

node main.js

Prüfungen ausführen (learnrun.js muss im selben Ordner liegen):

node --test
learnrun.js herunterladen

Häufige Fehler

Mit eckigen Klammern statt mit set speichern

const prices = new Map();
prices["tea"] = 3;
console.log(prices.get("tea").toFixed(2));

Was Node.js ausgibt

TypeError: Cannot read properties of undefined (reading 'toFixed')

Warum, und die Lösung

prices["tea"] = 3 fügt dem Map-Objekt eine gewöhnliche Eigenschaft hinzu. Die Einträge der Map bleiben leer, prices.get("tea") ist also undefined. Schreiben Sie mit prices.set("tea", 3) und lesen Sie mit prices.get("tea"). Dasselbe gilt für has, delete und size: Sie sehen nur Einträge, die mit set angelegt wurden.

Ein Objekt an new Map übergeben

const prices = new Map({ tea: 3, cake: 4 });
console.log(prices.size);

Was Node.js ausgibt

TypeError: object is not iterable (cannot read property Symbol(Symbol.iterator))

Warum, und die Lösung

new Map will eine Liste von [key, value]-Paaren, kein einfaches Objekt. Machen Sie das Objekt zuerst zu Paaren: new Map(Object.entries({ tea: 3, cake: 4 })). Der Weg zurück ist Object.fromEntries(map).

Anhängen, bevor die Gruppe existiert

const byPage = new Map();
for (const [visitor, page] of [["ada", "/home"], ["bo", "/blog"]]) {
  byPage.get(page).push(visitor);
}

Was Node.js ausgibt

TypeError: Cannot read properties of undefined (reading 'push')

Warum, und die Lösung

Beim ersten Auftreten einer Seite hat die Map noch kein Array dafür, get liefert also undefined, und push scheitert. Legen Sie für einen neuen Schlüssel zuerst das Array an: if (!byPage.has(page)) byPage.set(page, []); dann byPage.get(page).push(visitor). Wo ES2026-getOrInsert existiert, erledigt byPage.getOrInsert(page, []).push(visitor) beides.

JavaScript im Browser: die eigene Engine Ihres Browsers in einem abgeschotteten Worker. Syntaxfehler findet acorn 8.18.0, MIT. Lizenz und Quellcode

Abschlussquiz

5 Fragen, ohne Hinweise. Ab 80 % ist die Lektion abgeschlossen.

Erledigen Sie zuerst alle Aufgaben oben, um das Abschlussquiz freizuschalten.

Problem melden

Etwas ist falsch oder unklar? Beschreiben Sie es kurz, dann wird es geprüft und korrigiert.

#

Mindestens 20 Zeichen.

Nur, wenn Sie eine Antwort wünschen.

Kernideen

Map: beliebiger Schlüssel, in Reihenfolge

Eine Map hält Schlüssel-Wert-Paare. map.set(key, value) fügt hinzu oder ersetzt, map.get(key) liest (undefined, wenn es fehlt), map.has(key) fragt nach, map.delete(key) entfernt und map.size zählt. Anders als ein Objekt, dessen Schlüssel immer Strings oder Symbole sind, behält eine Map jeden Wert als Schlüssel: Die Zahl 1 und der String "1" sind zwei Schlüssel, und ein Objekt als Schlüssel wird nur über dasselbe Objekt gefunden, nicht über ein gleich aussehendes. Eine for...of-Schleife über eine Map liefert [key, value]-Paare in der Reihenfolge, in der die Schlüssel zuerst gesetzt wurden. Nutzen Sie set und get, nicht map[key]: Eckige Klammern legen eine gewöhnliche Eigenschaft an, die die Map nicht sieht.

Set und Umwandeln

Ein Set behält jeden Wert einmal: add(value), has(value), delete(value) und size. new Set(array) entfernt Duplikate, und [...set] oder Array.from(set) macht daraus wieder ein Array in der Reihenfolge des ersten Auftretens. Wie Map-Schlüssel werden Objekte in einem Set nach Identität verglichen, zwei getrennte [1, 2]-Arrays sind also zwei Werte. Zum Umwandeln: new Map(Object.entries(object)) macht aus einem Objekt eine Map, Object.fromEntries(map) macht aus einer Map wieder ein Objekt (für JSON.stringify, das eine Map als {} ausgibt), und [...map] liefert ein Array aus [key, value]-Paaren.

Zählen und Gruppieren

Zum Zählen lesen Sie den alten Zähler mit einem Default und schreiben ihn zurück: counts.set(word, (counts.get(word) ?? 0) + 1). Zum Gruppieren sorgen Sie zuerst dafür, dass ein Array existiert, und hängen dann an: if (!map.has(key)) map.set(key, []); map.get(key).push(item). Map.groupBy(items, fn) gruppiert ein ganzes Array in einem Aufruf. ECMAScript 2026 ergänzt map.getOrInsert(key, defaultValue), das den vorhandenen Wert zurückgibt oder den Default einfügt: map.getOrInsert(key, []).push(item). Node.js 24 hat es noch nicht, daher prüft dieser Kurs das has/set-Muster. Ihr Browser hat es vielleicht schon; prüfen Sie mit typeof Map.prototype.getOrInsert === "function".

Quellen

Zuletzt geprüft am 5. Oktober 2026