Graf Zahl: Arrays filtern, zaehlen, ausgeben

Hallo!

Gegeben ist folgendes:
ein mehrdimensionales Array, das eine Datenbanktabelle wiedergibt

Ausgabe des Arrays in eine HTML Tabelle, ausgesuchte Zeilen anhand der Werte in einer Array "spalte" (beim Erstellen der Tabelle wird einfach geschaut, ob in der Spalte der bestimmte Wert auftaucht)
Es gibt Daten fuer 3 Wochen. Interessant ist immer der Zustand einer Woche.

Jetzt sollen Zeilen gefiltert werden. Das heisst, es gibt in der Tabelle bestimmte Felder, die zusammen etwas wie eine Adresse ergeben. (genauer einen Start- und Endpunkt) Diese Kombi kann bis zu 5x pro Woche vorkommen. Der Filter (bisher nur eine Liste von Radiobuttons) soll alle ausgeben die mindestens so oft in besagter Woche vorkommen.

Dazu habe ich im Moment jeder Zeile einen Index aus Adresse und Wochennummer verpasst der jetzt eben bis zu 5x vorkommen kann:

row[i].adresse = row[i][2]+row[i][3]+woche

Es fehlt noch die Anzahl pro Woche. Ich kann jetzt eine Schleife dahernehmen und bei jeder Zeile mit einer anderen Schleife nachsehen, ob es den Eintrag schon gibt um dann einen Counter (row[i].adresser.counter) zu erhohen. Dazu muss ich aber wieder eine Schleife nehmen um jedem Eintrag mit dieser Adresskombination den richtigen Wert zu verpassen.

Ich kann auch ein zweites Array hernehmen und dort Funde vermerken.

Das scheint mir aber alles zu kompliziert. Sehe ich eine bessere Methode nicht? Oder hat jquery da eine passende Funktion? Was kann ich besser machen?

Das Problem ist also nicht, es hinzubekommen, sondern es nicht zu kompliziert zu machen.

  1. Hallo,

    Das scheint mir aber alles zu kompliziert. Sehe ich eine bessere Methode nicht? Oder hat jquery da eine passende Funktion? Was kann ich besser machen?

    Zeige uns mal ein vereinfachtes Beispiel. Eingabedaten, Filterinterface und gewünschte Ausgabe. So abstrakt kann man da schwer etwas zu sagen.

    Generelle Tipps: Bringe die Daten in ein Format, das du in JavaScript gut verarbeiten kannst. Das ist z.B. ein Array mit Objects. Objekteigenschaften mit selbst vergebenen Namen sind viel sprechender als Arrayindizes. Dann transformiere die Daten so, dass du sie gut filtern kannst. Eine String-ID zu erzeugen, die sich aus Einzeldaten zusammensetzt, ist schon einmal eine gute Idee. Damit reduziert sich die Vergleichszeit. Natürlich kannst du ähnliche Datensätze auch in einem Object unter einem gemeinsamen Namen gruppieren (Object mit Arrays), um später schneller darauf zuzugreifen: { 'id1': [record1, record2, …], 'id2': […] }

    jQuery ist für die Arbeit mit dem DOM gedacht, mehr nicht. Was du hier vorhast, hat mit dem DOM nichts zu tun. Das DOM ist nur letztlich zur Ausgabe/Visualisierung nötig. Interessant ist die Datenverarbeitung davor, das solltest du tunlichst von der Ausgabe trennen.

    Für den Umgang mit »Daten« gibt es allgemeine Bibliotheken wie Lodash bzw. Underscore. Für das Mapping von Daten auf DOM-Elemente kann man jQuery verwenden oder spezielle Bibliotheken wie D3.js.

    Ich würde dir raten, auf jeden Fall einmal Lodash anzusehen. Da ist keine Magie drin, sondern nur Umsetzungen von einschlägigen Operationen für Objekte und Listen (Map, Reduce, Filter, Grouping…). Vieles bietet JavaScript mittlerweile auch selbst, siehe die Array-Methoden.

    Mathias

    1. Hi!

      Ich habe sowas wie das hier. (ne Ecke mehr Daten aber vom Prinzip stimmt es)
      Berlin; 2/10/2014; Berlin Flughafen; 20/10/2014 14:31:00; ID BERLIN
      Berlin; 2/10/2014; Hannover; 02/10/2014 15:27:00; ID BERLIN
      Berlin; 2/11/2014; Hannover; 02/10/2014 15:15:00; ID BERLIN
      Hannover; 2/10/2014; Herne; 02/10/2014 17:30:00; ID HANNOVER
      Bayreuth; 2/11/2014; Stuttgart; 02/11/2014 20:09:00; ID BAYREUTH

      Per split wird ein Array erstellt (row[]) und in jede Zeile wird auch nochmal gesplittet (row[][])

      Bisher gibts 2 funktionierende Filteroptionen. Eine Gruppe Radiobuttons, die anhand des Vorhandenseins der ID unterscheidet (es wird eine spezielle generiert, fals keine vorhanden) und eine Selectbox die anhand der IDs filtert. Das funktioniert auch. Es gibt eine Funktion die das Array ausliest und eine Tabelle erstellt. Die wurde den onchange Events der Formularelemente angeklebt.

      Noch nicht belegt ist eine Gruppe Radiobuttons 1-5 pro Woche.

      Jetzt soll es mehr Filter geben. Eben den Tagesfilter. Im obigen Beispiel gibt es die Fahrt Berlin-Hannover zum Beispiel 2x in einer Woche. Klickt man in der Selectbox auf ID BERLIN werden alle Berliner angezeigt. Wenn man jetzt auf 2 klickt, sollen nur die beiden Fahrten Berlin-Hannover angezeigt werden.

      Ich habe den "Zeilen" ja noch den Identifier verpasst. Besagte Berlin-Hannover Fahrten sehen dann so aus:
      row[1].fahrt = "BerlinHannover7"
      row[2].fahrt = "BerlinHannover7"

      Eine Fahrt eine Woche vorher hat dann analog "BerlinHannover6" und ist damit eindeutig zu unterscheiden.

      Meine Idee bisher ist sowas:
      row[1].fahrt.counter = 2
      row[2].fahrt.counter = 2

      oder row[1].counter = 2 ...

      Damit kann ich die Funktion, die die Tabelle erstellt, bequem erweitern, nur Daten zu lesen die im Counter mindestens den Wert haben der in der Tage pro Woche Gruppe angeklickt ist.

      Aber auf den Wert des Counters zu kommen ist genau das was ich mit x Schleifen als zu kompliziert (langwierig) empfinde. Ich komme aber auch nicht auf was eleganteres.

      Die Array-Methoden sind mir wohl bekannt. Aber entweder helfen sie mir nicht oder ich sehe was nicht. Sonst stell ich mich auch nicht so an, aber ich hab hier wiedermal irgendwie eine Blockade.

      Gruss Graf Zahl
      (der nicht zählen kann)

      1. Hallo,

        Du denkst hier über Caching nach, welches das wiederholte Durchsuchen der Liste vereinfacht. Caching ist nur nötig, wenn das erneute Filtern der Daten zu schwierig oder zu langsam ist. Vor allem, wenn es verschiedene Filterdimensionen gibt, so ist ein wiederholter Map-Reduce ohne großes Caching vielleicht einfacher – nicht unbedingt schneller, aber wenn es nicht gerade 100.000 Datensätze sind, fällt das nicht ins Gewicht.

        Falls du Metadaten erzeugst, um das Filtern zu vereinfachen, so müsstest du die verschiedenen Filterdimensionen berücksichtigen. Man kann hier, wie bereits vorgeschlagen, weitere Objekte erzeugen, die die Fahrten gruppiert enthalten. Vollständig wäre: Nach Woche, dann nach ID (letzte Zeile), dann nach Start-Ziel-ID, dann ein Array mit den Fahrten.

          
        var fahrt1 = { id: '1', woche: '6', stadt: 'BERLIN', datum: new Date(), ankunft: new Date() }; // oder was auch immer die Spalten bedeuten  
        var hash = {  
          '6': {  
            'BERLIN': {  
              'Berlin-Hannover': [  
                fahrt1  
              ]  
            }  
          }  
        };
        

        Erzeugen kann ich eine solche Struktur mit Lodash-Helfern, z.B. mit mehreren groupBy.

        Ob diese Verschachtelung nötig ist, weiß ich nicht. Bei dieser Hashstruktur kann ich manches schnell nachschlagen, muss aber, je nachdem wie hoch ich ansetze, merge, map bzw. flatten verwenden, um an die letztlichen Fahrten zu kommen. Wenn ich nach einer Woche, einer Stadt und Strecke filtere, dann ist die Struktur gut:

        var fahrten = hash[woche][stadt][strecke];  
        fahrten[i]  
        fahrten.length
        

        Wenn ich nur nach Strecke filtere, muss ich die erste und zweite Ebene durchlaufen bzw. auflösen, damit ich alle Fahrten durchsuche. Da wären weitere Gruppierungs-Objekte sinnvoll.

        Ich würde hier erst einmal versuchen, ohne solche Hashes zu arbeiten, sondern rein funktional (d.h. ohne Änderung der Ausgangs-Datenstruktur) die Liste anhand aller Kriterien zu filtern. Das Kriterium »es müssen mindestens X Einträge existieren, auf die Y zutrifft« lässt sich mit groupBy bzw. countBy umsetzen.

        Map-Reduce und rein funktionale Programmierung sind hier die Richtungen, die ich empfehlen kann. Die genannten Tools sind dafür gut geeignet.

        Mathias