npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

compose-transducers

v1.0.8

Published

This package combines functional composition and transducers to allow high performance operations from arrays and minimal garbage collection.

Downloads

126

Readme

Compose Transducers

FOSSA Status

NPM

Build Status Downloads dependencies Status devDependencies Status Greenkeeper badge

This package combines functional composition and transducers to allow high performance operations from arrays (or other iterables) with minimal garbage collection. Under the hood we utilise transducer.js and function composition to allow you to build highly efficient data pipelines.

Installation

To install simply run:

Yarn:

yarn add compose-transducers

NPM:

npm install compose-transducers --save

Usage

This package support map, filter and reduce. After creating your operations list composeTransducer will return a function which you can reuse as much as you want. Example are below:

map/filter

Below is the function signature in typescript:

composeTransducer([{
  type: 'map' | 'filter' ;
  funcs: Function[];
}], mode = 'standard') => (source: any[], initialValue = []) => Array<any>

The example using map & filter at the same time:

// Import package
import { composeTransducer } from 'compose-transducers'

// Define example 'input'
const input = [1,2,3,4,5]

// Build operation list
const operationList = [{
  type:'map',
  funcs: [addTwo, multiplyByTen, divideByThree] // Array of "map" functions
}, {
  type: 'filter',
  funcs:[filterLessThanTen, filterLessThanOFourteen] // Array of "filter" functions
}]

// Build a transducer to use & reuse later
const composedTransducer = composeTransducer(operationList)

// Get the output
const output = composedTransducer(input) // composedTransducer(source, initialValue)

// Show output
console.log(output)

NOTE: You can have the map functions taking more than one parameter as long as your functions return the same number of parameters.

reduce

Below is the function signature in typescript:

composeTransducer([{
  type: 'map' | 'filter';
  funcs: Function[];
}], mode = 'reduce') => (source: any[], reducer: Reducer<any, any>, initialValue: any) => any

The above example but with a reduce to add all the numbers in the array:

// Import package
import { composeTransducer } from 'compose-transducers'

// Define example 'input'
const input = [1,2,3,4,5]

// Build operation list
const operationList = [{
  type:'map',
  funcs: [addTwo, multiplyByTen, divideByThree] // Array of functions taking single input
}, {
  type: 'filter',
  funcs:[filterLessThanTen, filterLessThanOFourteen]  // Array of functions taking single input
}]

// Build a transducer to use & reuse later
const composedTransducer = composeTransducer(operationList, 'reduce')

// Get the output
const output = composedTransducer(input, addAllNumbers, 0) // composedTransducer (input, reducerFunction, initialValue)

// Show output
console.log(output)

Description

Often, when we process data, it’s useful to break up the processing into multiple independent, composable stages. For example, it’s very common to select some data from a larger set, and then process that data (map / filter).

Problem

You may be tempted to do something like this:

// Define example 'input'
const input = [1,2,3,4,5]

// Define my operations
const addTwo = number => number + 2
const multiplyByTen = number => number * 10
const divideByThree = number => number / 3
const filterLessThanTen = number => number > 10
const filterLessThanOFourteen = number => number > 14

// Get output
const output  = input.map(addTwo)
                     .map(multiplyByTen)
                     .map(divideByThree)
                     .filter(filterLessThanTen)
                     .filter(filterLessThanOFourteen)

// Show output
console.log(output)

The problem with the above is for each map or filter you execute it returns a brand new array each time meaning we have just created five arrays in the code above.

All these arrays will eventually need to be garbage collected which if the array is very big (and you're creating new objects with each operation) this will cause unnecessary memory usage and potential blocking (if you are doing this on the frontend).

Solution

This package fixes this by composing the map and filter functions like so:

.map(addTwo).map(multiplyByTen).map(divideByThree) into const applyMaps = (x) => divideByThree(multiplyByTen(addTwo(x)))

.filter(filterLessThanTwo).filter(filterLessThanOne) into const applyFilters = (x) => [filterLessThanTen, filterLessThanOFourteen].every(fn => fn(x))

NOTE: Filter has to be done at the transducer level so ordering of the functions is important!

This will turn the above into:

// Get output
const output  = input.map(applyMaps).filter(applyFilters)

Now we are only creating two transient arrays instead of five which is an improvement but we can do more and this is where transducers come in. Instead of creating two transient arrays each element will pass through applyMaps and applyFilters before being placed into the output array.

This in effect means we take an input, perform ALL operations on it and place the results into a new array. This means we only create one array after this operation, which is the output array. This results in less GC and faster performance especially on the browser.

Contributing

All contributions are very welcome, please read my CONTRIBUTING.md first. You can submit any ideas as pull requests or as GitHub issues. If you'd like to improve code, please feel free!