Multidimensionale Daten – Programmieren lernen mit JavaScript – Thytos
Nächstes Video startet in 3 Sekunden.
Programmieren lernen mit JavaScript

Multidimensionale Daten

Stehen Da­ten mit­ein­an­der in Be­zie­hung, kön­nen neue In­for­ma­tio­nen aus ih­nen in­ter­pre­tiert wer­den. Je tie­fer Da­ten ver­schach­telt sind, des­to grö­ßer wird ihr Deu­tungs­raum.

Ein einfaches Array der Besetzung des Films Das Schweigen der Lämmer könnte folgendermaßen aufgebaut sein.

[
  "Anthony Hopkins",
  "Jodie Foster",
  "Kasi Lemmons",
  …
]

Statt einer Liste der Schauspielernamen kann eine Liste mit einfachen Objekten erstellt werden, die auch das Geburtsdatum und das Geschlecht der Schauspieler beinhalten.

[
  {
    name: "Anthony Hopkins",
    gender: "male",
    birthday: new Date(1937, 11, 31)
  }, {
    name: "Jodie Foster",
    gender: "female",
    birthday: new Date(1962, 10, 19)
  }, {
    name: "Kasi Lemmons",
    gender: "female",
    birthday: new Date(1961, 1, 24)
  }
]

Was ist hier passiert? Die Liste an Schauspielernamen wurde zu einer Tabelle gemacht. Jeder Eintrag entspricht einer Tabellenzeile; die Keys der einfachen Objekte sind die Spaltennamen der Tabelle.

Name Gender Birthday
Anthony Hopkins M 31.12.1937
Jodie Foster F 19.11.1962
Kasi Lemmons F 24.02.1962

Eine einfache Liste ist eine eindimensionale Datenstruktur; eine Tabelle dagegen eine zweidimensionale. Je tiefer die Daten verschachtelt sind, desto mehr Dimensionen erhalten sie.
Statt einer einzelnen mehrfach verschachtelten Struktur können Zusammenhänge in Daten auch durch Beziehungen repräsentiert werden. Das ist sogar das gewöhnlichere Vorgehen: Statt alle Informationen eines Schauspielers in der Besetzungsliste eines Filmes zu speichern, werden diese eher in einer Personen-Datenbank abgelegt – die Besetzungsliste enthält dann nur noch Referenzen zu den Personen in der Datenbank, beispielsweise in Form von IDs.

Die Bedeutung von Datenbeziehungen

Eine einfache Liste gibt verhältnismäßig wenig Raum zum Interpretieren der Daten. Eine Tabelle dagegen schon eher.

Die folgende Funktion kann aus der oben beschriebenen zweidimensionalen Datenstruktur alle weiblichen Besetzungsmitglieder auslesen und zurückgeben.

function women (arr) {
  for (var resArr = [], i = 0; i < arr.length; i++) {
    if (arr[i].gender === "female") {
      resArr.push(arr[i]);
    }
  }
  return resArr;
}

Ausgeführt, gibt es die Objekte von Jodie Foster und Kasi Lemmons zurück.

women(cast);
// => [{ name: "Jodie Foster", … }, { name: "Kasi Lemmons", … }]

Das gleiche kann natürlich auch für männliche Besetzungsmitglieder gemacht werden.

function men (arr) {
  for (var resArr = [], i = 0; i < arr.length; i++) {
    if (arr[i].gender === "male") {
      resArr.push(arr[i]);
    }
  }
  return resArr;
}

Wird dieser Funktion das cast-Array übergeben, wird das Objekt von Anthony Hopkins zurückgegeben.

men(cast);
// => [{ name: "Anthony Hopkins", … }]

Genauso kann das Alter der Schauspieler ausgelesen und verglichen werden. Date-Objekte haben den Vorteil, dass sie mit Vergleichsoperatoren miteinander verglichen werden können.
Die beiden Funktionen oldest und youngest liefern das älteste bzw. jüngste Besetzungsmitglied zurück.

function oldest (arr) {
  for (var oldest = arr[0], i = 1; i < arr.length; i++) {
    if (arr[i].birthday < oldest.birthday) {
      oldest = arr[i];
    }
  }
  return oldest;
}

function youngest (arr) {
  for (var youngest = arr[0], i = 1; i < arr.length; i++) {
    if (arr[i].birthday > youngest.birthday) {
      youngest = arr[i];
    }
  }
  return youngest;
}

Anthony Hopkins und Jodie Foster sind die ältesten bzw. jüngsten Besetzungsmitglieder.

oldest(cast);
// => { name: "Anthony Hopkins", … }

youngest(cast);
// => { name: "Jodie Foster", … }

Das tolle: Diese Funktionen können nun sogar miteinander kombiniert werden. Wird der Rückgabewert von women der oldest-Funktion übergeben, liefert es die älteste Frau aus der Besetzung.

oldest(women(cast));
// => { name: "Kasi Lemmons", … }

Der Informationsgehalt ist in diesem Beispiel noch immer gering, weil die Daten nur drei Schauspieler aus einer einzelnen Besetzungsliste umfassen. Dennoch zeigt allein schon dieses begrenzte Beispiel, wie sehr sich der Interpretationsraum vergrößert, wenn die Datenstruktur um eine Dimension erweitert wird.
Je mehr Daten vorliegen, die miteinander in Beziehung stehen, desto größer wird der Deutungsraum und der Informationsgehalt dieser Daten, sprich: desto mehr Bedeutung erhalten sie.

Das ist mit ein Grund dafür, dass Unternehmen wie Google, Facebook, Netflix und Co so viele Daten speichern wie sie erheben können, selbst wenn ihnen zum Zeitpunkt des Speicherns nicht mal klar ist, wie sie die Daten deuten wollen.

Generalisierung der Funktionen

Die erstellten Funktionen women, men, youngest und oldest sind sehr spezifisch für die cast-Liste angelegt.
Außerdem sind women und men fast gleiche Funktionen, nur dass sie sich im Wert unterscheiden, nach dem gefiltert wird.
Das lässt sich verallgemeinern.

Statt youngest und oldest werden die Funktionen maximum und minimum angelegt. Auch wird nicht fest die birthday-Eigenschaft untersucht, sondern eine Eigenschaft, die per Argument übergeben wird.

function maximum (arr, prop) {
  for (var maximum = arr[0], i = 1; i < arr.length; i++) {
    if (arr[i][prop] > maximum[prop]) {
      maximum = arr[i];
    }
  }
  return maximum;
}


function minimum (arr, prop) {
  for (var minimum = arr[0], i = 1; i < arr.length; i++) {
    if (arr[i][prop] < minimum[prop]) {
      minimum = arr[i];
    }
  }
  return minimum;
}

Die Funktionen können nun genauso wie youngest und oldest verwendet werden, nur dass "birthday" als Parameter beim Funktionsaufruf mit übergeben werden muss.

maximum(cast, "birthday"); // Entspricht youngest(cast);
// => [{ name: "Jodie Foster", … }]

minimum(cast, "birthday"); // Entspricht oldest(cast);
// => [{ name: "Anthony Hopkins", … }]

Die women- und men-Funktionen werden durch die einzelne Funktion where ersetzt. Diese filtert das übergebene Array nach Objekten, in denen eine übergebene Property einem übergebenen Wert entspricht.

function where (arr, prop, val) {
  for (var resArr = [], i = 0; i < arr.length; i++) {
    if (arr[i][prop] === val) {
      resArr.push(arr[i]);
    }
  }
  return resArr;
}

Mit dieser einen Funktion können die Ergebnisse der beiden Funktionen women und men reproduziert werden.

where(cast, "gender", "female"); // Entspricht women(cast);
// => [{ name: "Jodie Foster", … }, { name: "Kasi Lemmons", … }]

where(cast, "gender", "male"); // Entspricht men(cast);
// => [{ name: "Anthony Hopkins", … }]

Durch die Generalisierung der Funktionen können diese auch auf andere Properties angewendet werden. Beispielsweise kann der Name verwendet werden, um die Daten zu einer bestimmten Person auszugeben.

where(cast, "name", "Kasi Lemmons")[0];
// => { name: "Kasi Lemmons", gender: "female", birthday: … }