На самом деле, если не боитесь изучить новую абстракцию (не такую уж и сложную, на самом-то деле), посмотрите на
трансдьюсеры. Эта абстракция как раз позволяет комбинировать функции вроде filter и map без лишних проходов по коллекции. На Clojure[Script] Ваш пример выглядел бы следующим образом:
(def exists #(.exists (clojure.java.io/as-file %)))
(def process-files
(comp
(map #(do-something %)))
(filter #(exists (:path %))))
(sequence process-files audios)
В JS трансдьюсеры реализованы в
Ramda, выглядеть на JS это будет как-то так:
import { compose, filter, into, map } from 'ramda';
const processFiles = compose(
map(audio => doSomething(audio)),
filter(audio => fs.existsSync(audio.path))
);
into([], processFiles, audios);
UPD: Есть ещё такое ad-hoc решение: написать функцию-хелпер
filterMap
, которая внутри будет императивной, но при использовании будет выглядеть вполне нормально:
function filterMap(filterFn, mapFn) {
return arr => {
const newArr = [];
for (let x of arr) {
if (filterFn(x)) newArr.push(mapFn(x));
}
return newArr;
}
}
Использование:
const processFiles = filterMap(
audio => fs.existsSync(audio.path),
audio => doSomething(audio)
);
processFiles(audios);
Но такое решение куда менее расширяемо чем решение с трансьюсерами, да и на мой взгляд менее красиво.