dmc1989
@dmc1989

Как пропускать элементы в map?

Как правильно пропустить, и можно ли такое делать? Если файл не найден, то можно ли сформировать новый массив только из существующих файлов?
audios.map(function(audio) {    
        if (!fs.existsSync(audio.path)) {
            return; // File not found
        }
    // do something
}
  • Вопрос задан
  • 4472 просмотра
Решения вопроса 1
k12th
@k12th
console.log(`You're pulling my leg, right?`);
Не, нельзя. Можно потом сделать filter, но это не очень эффективно. Можно так же сделать с помощью reduce. Но проще всего обойти массив с помощью forEach, а существующие файлы положить в новый массив и работать с ним.
Как вариант -- старый добрый цикл, если критична производительность.

const existingFiles = [];
audios.forEach(function(audio) {    
        if (fs.existsSync(audio.path)) {
            existingFiles.push(audio);
        }
}
Ответ написан
Пригласить эксперта
Ответы на вопрос 1
На самом деле, если не боитесь изучить новую абстракцию (не такую уж и сложную, на самом-то деле), посмотрите на трансдьюсеры. Эта абстракция как раз позволяет комбинировать функции вроде 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);

Но такое решение куда менее расширяемо чем решение с трансьюсерами, да и на мой взгляд менее красиво.
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы