Git Product home page Git Product logo

gossie / array-pipe Goto Github PK

View Code? Open in Web Editor NEW
7.0 3.0 2.0 262 KB

A polyfill written in TypeScript, that adds a pipe method to arrays, allowing developers to implement "short-circuit evaluation" of operations on arrays.

Home Page: https://github.com/gossie/array-pipe/blob/master/README.md

License: MIT License

JavaScript 1.84% TypeScript 98.16%
javascript typescript array pipe polyfill pipe-polyfill short-circuit

array-pipe's Introduction

Build Status Mutation testing badge

array-pipe

The project defines a pipe method as a polyfill for arrays, that enables developers to perform multiple operations with only iterating over as few elements as possible.
Imagine you have an array of string encoded numbers and want to check if there is one that is dividable by two.

const result: boolean = ['1', '2', '3', '4', '5', '6', '7', '8', '9', '10']
    .map((s: string) => parseInt(s))
    .some((n: number) => n%2 === 0);

The code does what it is supposed to. But it will iterate over the whole array mapping all elements before checking the dividability. Using the pipe polyfill would look like this:

const result: boolean = ['1', '2', '3', '4', '5', '6', '7', '8', '9', '10']
    .pipe(
        map((s: string) => parseInt(s)),
        some((n: number) => n%2 === 0)
    );

The pipe polyfill with its operators will get the same result, but it won't map all elements before the check. Each element will be handled by all operators (or if the element doesn't match a filter operator) before the next element is processed. As soon as a result is found, it is returned and the handling is stopped.
The following table illustrates how the elements are streamed throught the operators.

map operator some operator
Step 1 '1' '1' is mapped
Step 2 1 1 is checked -> check fails
Step 3 '2' '2' is mapped
Step 4 2 2 is checked -> check succeeds and true is returned by the pipe

No more elements are mapped or checked, because it is not necessary.

Current Operators

Intermediate Operators

There can be as many intermediate operators as you want in a pipe. In an intermediate operator is the last operator of a pipe, the result of the pipe call will be an array.

  • filter
    Gets a function that takes an element and returns a boolean. The elements where the function returns true survive.
  • map
    Gets a function and applies each element to that function.
  • flatMap
    The operator gets a function that maps to an array of elements and flattens them.
  • distinct
    Removes duplicated elements. It's important to note, that this is a statefull operator.

Terminal Operators

A terminal operator has to be the last one in a pipe. Also, there can only be on terminal operator in a pipe.

  • find
    Gets a function that takes an element and returns a boolean. If an element is evaluated to true that element is immediately returned by the pipe.
  • some
    Some works similar to the first-operator except that not the element is returned, but the value true as soon as the passed function evaluates to true.
  • every
    every also applies the passed function to each element. As soon as one element does not evaluate to true the pipe immediately returns false.
  • none
    none also applies the passed function to each element. As soon as one element evaluates to true the pipe immediately returns false.
  • reduceToSome
    Checks if there are two consecutive elements that fullfill the constraint passed. If a pair is found true is returned immediately.
const result: boolean = [1, 2, 4, 5]
    .pipe(
        reduceToSome((n1: number, n2: number) => (n1+n2)%2 === 0)
    )

result would be true because (2+4)%2 === 0 is true. The pair of 4 and 5 would not be checked.

  • reduceToEvery
    Checks if every two consecutive elements fullfill the constraint passed. If a pair is found that does not, false is returned immediately.
const result: boolean = [1, 3, 4, 6]
    .pipe(
        reduceToEvery((n1: number, n2: number) => (n1+n2)%2 === 0)
    )

result would be false because (3+4)%2 === 0 is false. The pair of 4 and 6 would not be checked.

  • reduceToNone
    Checks if no two consecutive elements fullfill the constraint passed. If a pair is found that does, false is returned immediately.
const result: boolean = [1, 2, 4, 5]
    .pipe(
        reduceToNone((n1: number, n2: number) => (n1+n2)%2 === 0)
    )

result would be false because (2+4)%2 === 0 is true. The pair of 4 and 5 would not be checked.

Write your own operator

You might have the need to write your own operator.
The easiest way is, to extend either IntermediateOperator or TerminalOperator. In this example an operator is implemented that returns the sum of the first n elements, where the n is passed a the limit Parameter.
All you need to do then, is implement the perform method and, in case of a TerminalOperator, the getFallbackValue method. The gets passed an element from the array and returns an OperatorResult. The OperatorResult contains the resulting value of the operation and some other information. For a TerminalOperator it needs to contain a done attribute that tells the pipe, if it can stop the execution or has to go on. An IntermediateOperator does not need the done attribute but can contain an option skip attribute. That tells the pipe if the value will be part of the result or not.

import { TerminalOperator } from '@gossie/array-pipe/operators';

class LimitedSumOperator extends TerminalOperator<number, number> {

    private sum = 0;
    private iterations = 0;

    constructor(private limit: number) {
        super();
    }

    public perform(from: number): OperatorResult<number> {
        ++this.iterations;
        this.sum += from;
        return {
            value: this.sum,
            done: this.iterations == this.limit
        };
    }

    public getFallbackValue(): number {
        return 0;
    }
}

After you implemented the operator class you can export a function that returns an instance of your operator.

export function limitedSum(n: number): Operator<number, number> {
    return new LimitedSumOperator(n);
}

Then you can use your custom operator like the others.

const result: number = ['1', '2', '3', '4', '5', '6', '7', '8', '9', '10']
    .pipe(
        map((s: string) => parseInt(s)),
        limitedSum(5)
    );

The result should be 15.

When is it usefull to use array-pipe?

If your code always needs to perform all operations on all elements in your array, you probably should stick to the original JavaScript methods. The pipe is only usefull if you use a terminal operator as last operator.
Another case for using the pipe would be, if you need to write your own operator.

Integration

After you installed the npm dependency you need to import @gossie/array-pipe so that the polyfill is activated. In addition the operators you want to use need to be imported. For the example above, it would look like this:

import '@gossie/array-pipe';
import { map, some } from '@gossie/array-pipe/operators';

Try it out

Go to the array-pipe Test application to compare different implementations.

array-pipe's People

Contributors

gossie avatar madnight avatar wilgert avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

Forkers

wilgert madnight

array-pipe's Issues

New operators

  • Boolean every (short circuit)
  • Boolean none (short circuit)
  • Boolean some (short circuit)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.