Рубрики
Без рубрики

Как сделать ваши данные преобразования более эффективными с помощью преобразователей

При эффективных данных Guido Schmitz преобразования данных с использованием трансметриспредрансформенных крупных коллекций данных могут быть дорогими, особенно когда вы используете функции более высокого порядка, такие как карта и фильтр. Эта статья покажет мощность преобразователей для создания эффективных функций трансформации данных, которые не создают временные коллекции. Временные коллекции

Автор оригинала: FreeCodeCamp Community Member.

Гидо Шмице

Преобразование больших коллекций данных может быть дорогим, особенно когда вы используете Функции высшего порядка как карта и Фильтр Отказ

Эта статья покажет мощность преобразователей для создания эффективных функций трансформации данных, которые не создают временные коллекции. Временные коллекции создаются, когда карта и Фильтр Функции цепляются вместе. Это связано с тем, что эти функции возвращают новую коллекцию и пройдут результат к следующей функции.

Представьте себе записи 1 000 000 Люди и желающие создать подмножество «имен женщин выше 18 лет, которые живут в Нидерландах». Есть разные способы решения этого, но начнем с цепочка подход.

Если этот подход для вас нового, или вы хотите узнать больше об этом, я написал сообщение в блоге по использованию Функции высшего порядка Отказ

const ageAbove18 = (person) => person.age > 18;const isFemale = (person) => person.gender === 'female';const livesInTheNetherlands = (person) => person.country === 'NL';const pickFullName = (person) => person.fullName;
const output = bigCollectionOfData  .filter(livesInTheNetherlands)  .filter(isFemale)  .filter(ageAbove18)  .map(pickFullName);

Ниже приведена визуализация использования прикованного подхода, который создает временные массивы. Представьте себе счет зацикливания более 1 000 000 записей 3 раза!

Конечно, фильтрованные коллекции будут уменьшены на некоторое количество, но это все еще довольно дорого.

Ключевое понимание, однако, в том, что карта и Фильтр можно определить с использованием Уменьшить Отказ Давайте реализуем вышеуказанный код с точки зрения Уменьшить Отказ

const mapReducer = (mapper) => (result, input) => {  return result.concat(mapper(input));};
const filterReducer (predicate) => (result, input) => {  return predicate(input) ? result.concat(input) : result;};
const personRequirements = (person) => ageAbove18(person)  && isFemale(person)  && livesInTheNetherlands(person);
const output = bigCollectionOfData  .reduce(filterReducer(personRequirements), [])  .reduce(mapReducer(pickFullName), []);

Мы можем еще больше упростить Фильтрредка Используя Функциональная композиция Отказ

filterReducer(compose(ageAbove18, isFemale, livesInTheNetherlands));

При использовании этого подхода мы сокращаем (ха-ха!) Сколько раз мы создаем временный массив. Ниже приведена визуализация преобразования при использовании Уменьшить подход.

Красиво, верно? Но мы говорили преобразователями. Где наши преобразователи? Оказывается, Фильтрредка и MapReducer Мы создали Уменьшение функций Отказ Мы можем выразить это как:

reducing-function :: result, input -> result

Преобразователи – это функции, которые принимают Снижение функции и вернуть снижение функции. Это может быть выражено как следующее:

transducer :: (result, input -> result) -> (result, input -> result)

Самая интересная часть заключается в том, что преобразователи примерно симметричны в подписи их типа. Они принимают одну функцию снижения и возвращают другую.

Из-за этого мы можем составить любое количество преобразователей, использующих функциональную композицию.

Создание собственных преобразователей

Надеюсь, все начинает иметь больше смысла сейчас. Давайте построим наших собственных функций преобразователя для карта и Фильтр Отказ

const mapTransducer = (mapper) => (reducingFunction) => {  return (result, input) => reducingFunction(result, mapper(input));}
const filterTransducer = (predicate) => (reducingFunction) => {  return (result, input) => predicate(input)    ? reducingFunction(result, input)    : result;}

Использование преобразователей, которые мы создали выше, давайте преобразуем некоторые числа. Мы будем использовать составить Функция от Ramdajs.

Ramdajs это библиотека, которая обеспечивает практические функциональные методы и специально предназначена для стилей функциональных программирования.

const concatReducer = (result, input) => result.concat(input);const lowerThan6 = filterTransducer((value) => value < 6);const double = mapTransducer((value) => value * 2);
const numbers = [1, 2, 3];
// Using Ramda's compose hereconst xform = R.compose(double, lowerThan6);
const output = numbers.reduce(xform(concatReducer), []); // [2, 4]

ConcatredRucter называется Функция итератора Отказ Это будет призвано к каждой итерации и будет отвечать за преобразование вывода функции преобразователя.

В этом примере мы просто объединяем результат. Поскольку каждый преобразователь принимает только снижение функции, мы не можем использовать Value.concat Отказ

Когда мы составляем несколько преобразователей в одну функцию, большую часть времени это называется XForm преобразователь. Поэтому, когда вы видите это где-то, вы знаете, что это значит.

Составление нескольких преобразователей

Мы использовали обычную функциональную композицию в предыдущем примере, и вам может задаться вопросом, что такое порядок оценки. Хотя композиция функции применяется функции справа налево, преобразования фактически будут оценены слева направо при времени выполнения – что гораздо интуитивно понятно для тех из нас, кто читал в левостороннем языках.

Требуется немного мышления понять, почему это правда: учитывая наш преобразователь Двойной который возвращает снижение функции, а наш преобразователь Showerthan6 который также возвращает снижение функции, когда вы составляете Двойной и Showerthan6 , вывод Двойной будет передан Showerthan6 Затем, что затем вернет снижение функции Showerthan6 Отказ Таким образом, Двойной является результатом композиции и порядок оценки, действительно, слева направо.

Я создал JSBIN Пример С некоторыми console.log утверждения, так что вы можете взглянуть на него для себя.

Использование Ramdajs для повышения читаемости

Поскольку преобразователи являются идеальным примером для функционального стиля программирования, давайте посмотрим на то, как Ramda может помочь нам, используя их набор методов.

const lowerThan6 = R.filter((value) => value < 6);const double = R.map((value) => value * 2);const numbers = [1, 2, 3];
const xform = R.compose(double, lowerThan6);
const output = R.into([], xform, numbers); // [2,4]

С Ramda мы можем использовать их карта и Фильтр методы. Это потому, что внутренняя Уменьшить Метод использует Протокол преобразователя под капотом.

Заключение

Преобразователи – это мощный и композитивный способ создания преобразований, которые вы можете повторно использовать во многих контекстах. Как только у вас есть преобразователь, вы можете сделать открытый набор вещей.

Они особенно полезны при преобразовании больших наборов данных, но вы также можете использовать тот же преобразователь для преобразования одной записи.

Если вы хотите узнать больше об этой теме, я рекомендую следующие статьи:

https://clojure.org/reference/Transducers http://blog.cognitect.com/blog/2014/8/6/Transducers-) https://github.com/cognitect-labs/transducers-js#the-transducer-protocol

?? Если вам понравилось эту статью, нажмите эту кнопку CLAP ниже? Это будет много значить для меня, и это помогает другим людям видеть этот пост.

Следуйте за мной, чтобы получить уведомление для большего количества программирования контента такого.