Der gesamte Code verwendet die ES2015-Syntax. Wer die ES5-Syntax benötigt, kann zum Übersetzen Babel – Try it out oder TypeScript Playground verwenden.
Frage gestellt
Ein Freund hat mir heute eine Frage gestellt. Das Front-End erhält über Ajax eine große Datenmenge vom Back-End, die nach bestimmten Bedingungen gefiltert werden muss . Die Filtermethode ist wie folgt:
class Filter { filterA(s) { let data = this.filterData || this.data; this.filterData = data.filter(m => m.a === s); } filterB(s) { let data = this.filterData || this.data; this.filterData = data.filter(m => m.b === s); } }
Ich bin jetzt verwirrt und habe das Gefühl, dass es falsch ist, die Daten auf diese Weise zu verarbeiten, aber ich weiß nicht, wie ich sie verarbeiten soll.
Das Problem wurde gefunden
Das Problem liegt in der Filterung. Obwohl es möglich ist, eine Mehrfachfilterung zu erreichen (indem zuerst filterA() und dann filterB() aufgerufen werden), ist diese Filterung irreversibel. Angenommen, der Filtervorgang sieht folgendermaßen aus:
f.filterA("a1"); f.filterB("b1"); f.filterA("a2");
Ursprünglich wollte ich die Daten nach „a1“ und „b1“ filtern und dann die erste Bedingung in „a2“ ändern, aber das Ergebnis war so sei eine leere Menge.
Lösen Sie das Problem
Wenn Sie ein Problem finden, lösen Sie es entsprechend. Da dieses Problem durch den irreversiblen Filterprozess verursacht wird, kann das Problem gelöst werden, indem die Filterung jedes Mal direkt von this.data aus gestartet wird, anstatt von this.filterData aus. Wenn Sie dies tun möchten, müssen Sie zunächst die ausgewählten Filterbedingungen erfassen.
Filterbedingungen aufzeichnen
Es ist sicherlich möglich, Filterbedingungen in einer Liste aufzuzeichnen. Beachten Sie jedoch, dass sich zwei Filter für dieselbe Bedingung gegenseitig ausschließen und daher nur der letzte beibehalten werden kann Sie sollten HashMap verwenden, das besser geeignet ist.
class Filter { constructor() { this.filters = {}; } set(key, filter) { this.filters[key] = filter; } getFilters() { return Object.keys(this.filters).map(key => this.filters[key]); } }
In diesem Fall wird der obige Prozess ausgedrückt als
f.set("A", m => m.a === "a1"); f.set("B", m => m.b === "b1"); f.set("A", m => m.a === "a1"); let filters = f.getFilters(); // length === 2;
Der im 3. Satz oben festgelegte Filter deckt den im 1. Satz festgelegten Filter ab. Verwenden Sie nun die zuletzt erhaltenen Filter, um die Originaldaten this.data der Reihe nach zu filtern, und Sie erhalten das richtige Ergebnis.
Manche Leute denken vielleicht, dass die von getFilters() zurückgegebene Liste nicht in der Reihenfolge der Menge ist – tatsächlich ist dies das Merkmal von HashMap, das ungeordnet ist. Bei der Beurteilung einfacher Bedingungen ist das Ergebnis jedoch dasselbe, egal wer zuerst kommt. Bei manchen zusammengesetzten Zustandsbeurteilungen kann es jedoch Auswirkungen haben.
Bei Bedarf können Sie Array anstelle von Map verwenden, um das Reihenfolgeproblem zu lösen. Dies verringert jedoch die Sucheffizienz (lineare Suche). Wenn Sie das Problem der Sucheffizienz dennoch lösen möchten, können Sie es mithilfe einer Array-Karte lösen. Hier gibt es nicht viel zu sagen.
Filtern
Tatsächlich ist es bei der Verwendung sehr langsam, getFilter() zu verwenden und es dann jedes Mal mit einer Schleife zu verarbeiten. Da Daten in Filter gekapselt sind, können Sie erwägen, direkt eine filter()-Methode anzugeben, um die Filterschnittstelle bereitzustellen.
class Filter { filter() { let data = this.data; for (let f of this.getFilters()) { data = data.filter(f); } return data; } }
Ich denke jedoch, dass dies nicht sehr effizient ist, insbesondere wenn es um große Datenmengen geht. Sie können auch die verzögerte Verarbeitung von lodash nutzen.
Verzögerte Verarbeitung von lodash verwenden
filter() { let chain = _(this.data); for (let f of this.getFilters()) { chain = chain.filter(f); } return chain.value(); }
lodash aktiviert die verzögerte Verarbeitung, wenn die Daten größer als 200 sind, das heißt, es verarbeitet sie in einer Schleife und ruft nacheinander jeden Filter auf . Anstatt jeden Filter zu durchlaufen.
Der Unterschied zwischen verzögerter Verarbeitung und nicht verzögerter Verarbeitung ist in der Abbildung unten zu sehen. Bei der unverzögerten Verarbeitung werden insgesamt n (hier n = 3) große Schleifen ausgeführt, was zu n - 1 Zwischenergebnissen führt. Bei der verzögerten Verarbeitung wird nur eine große Schleife ausgeführt und es werden keine Zwischenergebnisse generiert.
Aber um ehrlich zu sein, lade ich nicht gerne eine zusätzliche Bibliothek für triviale Dinge, also mache ich einfach selbst eine einfache Implementierung
Verzögerungsverarbeitung implementieren Ich selbst
filter() { const filters = this.getFilters(); return data.filter(m => { for (let f of filters) { // 如果某个 filter 已经把它过滤掉了,也不用再用后面的 filter 来判断了 if (!f(m)) { return false; } } return true; }); }
Die for-Schleife im Inneren kann auch mit Array.prototype.every vereinfacht werden:
filter() { const filters = this.getFilters(); return data.filter(m => { return filters.every(f => f(m)); }); }
Datenfilterung ist eigentlich keine komplizierte Angelegenheit, solange Sie die Ideen klären Sie können verstehen, welche Daten aufbewahrt werden müssen, welche Daten temporär sind (Zwischenprozess) und welche Daten das Endergebnis sind. Sie können problemlos mithilfe der entsprechenden Methoden in Array.prototype oder Tools wie lodash verarbeitet werden.