TLDR: Sie können zuerst Ihr Array filtern und dann Ihre Zuordnung durchführen, dies würde jedoch zwei Durchgänge für das Array erfordern (Filter gibt ein Array an die Zuordnung zurück). Da dieses Array klein ist, sind die Leistungskosten sehr gering. Sie können auch eine einfache Reduzierung durchführen. Wenn Sie sich jedoch noch einmal vorstellen möchten, wie dies mit einem einzigen Durchgang über das Array (oder einen beliebigen Datentyp) erreicht werden kann, können Sie eine Idee namens "Transducer" verwenden, die von Rich Hickey populär gemacht wurde.
Antworten:
Es sollte nicht erforderlich sein, die Punktverkettung zu erhöhen und das Array zu bearbeiten, [].map(fn1).filter(f2)...da bei diesem Ansatz für jede reducingFunktion Zwischenarrays im Speicher erstellt werden .
Der beste Ansatz arbeitet mit der eigentlichen Reduktionsfunktion, sodass nur ein Datendurchlauf und keine zusätzlichen Arrays vorhanden sind.
Die Reduktionsfunktion ist die Funktion, die an reduceeinen Akkumulator und eine Eingabe von der Quelle übergeben wird und etwas zurückgibt, das dem Akkumulator ähnelt
// 1. create a concat reducing function that can be passed into `reduce`
const concat = (acc, input) => acc.concat([input])
// note that [1,2,3].reduce(concat, []) would return [1,2,3]
// transforming your reducing function by mapping
// 2. create a generic mapping function that can take a reducing function and return another reducing function
const mapping = (changeInput) => (reducing) => (acc, input) => reducing(acc, changeInput(input))
// 3. create your map function that operates on an input
const getSrc = (x) => x.src
const mappingSrc = mapping(getSrc)
// 4. now we can use our `mapSrc` function to transform our original function `concat` to get another reducing function
const inputSources = [{src:'one.html'}, {src:'two.txt'}, {src:'three.json'}]
inputSources.reduce(mappingSrc(concat), [])
// -> ['one.html', 'two.txt', 'three.json']
// remember this is really essentially just
// inputSources.reduce((acc, x) => acc.concat([x.src]), [])
// transforming your reducing function by filtering
// 5. create a generic filtering function that can take a reducing function and return another reducing function
const filtering = (predicate) => (reducing) => (acc, input) => (predicate(input) ? reducing(acc, input): acc)
// 6. create your filter function that operate on an input
const filterJsonAndLoad = (img) => {
console.log(img)
if(img.src.split('.').pop() === 'json') {
// game.loadSprite(...);
return false;
} else {
return true;
}
}
const filteringJson = filtering(filterJsonAndLoad)
// 7. notice the type of input and output of these functions
// concat is a reducing function,
// mapSrc transforms and returns a reducing function
// filterJsonAndLoad transforms and returns a reducing function
// these functions that transform reducing functions are "transducers", termed by Rich Hickey
// source: http://clojure.com/blog/2012/05/15/anatomy-of-reducer.html
// we can pass this all into reduce! and without any intermediate arrays
const sources = inputSources.reduce(filteringJson(mappingSrc(concat)), []);
// [ 'one.html', 'two.txt' ]
// ==================================
// 8. BONUS: compose all the functions
// You can decide to create a composing function which takes an infinite number of transducers to
// operate on your reducing function to compose a computed accumulator without ever creating that
// intermediate array
const composeAll = (...args) => (x) => {
const fns = args
var i = fns.length
while (i--) {
x = fns[i].call(this, x);
}
return x
}
const doABunchOfStuff = composeAll(
filtering((x) => x.src.split('.').pop() !== 'json'),
mapping((x) => x.src),
mapping((x) => x.toUpperCase()),
mapping((x) => x + '!!!')
)
const sources2 = inputSources.reduce(doABunchOfStuff(concat), [])
// ['ONE.HTML!!!', 'TWO.TXT!!!']
Ressourcen: Rich Hickey Transducer Post