Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

list-fns

Package Overview
Dependencies
Maintainers
1
Versions
10
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

list-fns

A collection of utility functions to be used with .map, .filter, .sort and .reduce

  • 1.1.0
  • Source
  • npm
  • Socket score

Version published
Weekly downloads
96
decreased by-46.37%
Maintainers
1
Weekly downloads
 
Created
Source

list-fns

npm version

This library contains higher order functions for doing common list operations to enable a more declarative style when working with lists. File size is prioritized over performance (several of the functions are O(n^2)); this is not recommended for use with very large datasets.

Example

import { byProperty, get, uniqueByProperty } from "list-fns";

const people = [
  { name: "Jack", age: 44 },
  { name: "Jack", age: 60 },
  { name: "Jane", age: 20 },
];

people
  .filter(
    (person, index) => index === people.findIndex(p => p.name === person.name)
  )
  .sort((a, b) => (a.age < b.age ? -1 : a.age > b.age ? 1 : 0))
  .map(person => person.name); // ["Jane", "Jack"]

people
  .filter(uniqueByProperty("name"))
  .sort(byProperty("age"))
  .map(get("name")); // ["Jane", "Jack"]

Install

npm install list-fns

Disclaimer about sorting

This library contains functions to be used with [].sort(). Always be mindful of the fact that .sort() and .reverse() will mutate the original list. If .sort() is the first method you're calling on a list you should probably clone it first in order to avoid unexpected behavior:

[...list].sort();
list.slice().sort();
[].concat(list).sort();

Functions

Table of contents

by

by: <T>(func: (el: T) => any) => (a: T, b: T) => 0 | 1 | -1

Use with: sort

Sort the elements by func(element) . Supports sorting by boolean values (elements that are true first).

[{ a: 2 }, { a: 1 }].sort(by(el => el.a)); // Returns [{ a: 1 }, { a: 2 }]

Implementation

const by = <T>(func: (el: T) => any) => (a: T, b: T) => {
  const A = func(a),
    B = func(b);
  if (typeof A === "boolean") return A && !B ? -1 : !A && B ? 1 : 0;
  return A < B ? -1 : A > B ? 1 : 0;
}

byProperty

byProperty: <TObject extends object, TKey extends keyof TObject>(key: TKey) => (a: TObject, b: TObject) => 0 | 1 | -1

Use with: sort

Sort the elements by element[key] (can also be an array index). Supports sorting by boolean values (elements that are true first).

[{ a: 2 }, { a: 1 }].sort(byProperty('a')); // Returns [{ a: 1 }, { a: 2 }]
[["a", 2], ["a", 1]].sort(byProperty(1)); // Returns [["a", 1], ["a", 2]]

Implementation

const byProperty = <TObject extends object, TKey extends keyof TObject>(
  key: TKey
) => by<TObject>(get(key))

byValue

byValue: (a: number, b: number) => 0 | 1 | -1

Use with: sort

Sort a list of numbers. This is useful because javascript sorts numbers as string, meaning that [25, 100] results in [100, 25] since "2" is greater than "1"

[100, 25].sort(); // Returns [100, 25]
[100, 25].sort(byValue); // Returns [25, 100]

Implementation

const byValue = (a: number, b: number) => (a < b ? -1 : a > b ? 1 : 0)

countBy

countBy: <T>(func: (el: T) => boolean) => (acc: number, el: T) => number

Use with: reduce

Returns the number of times func returned true for the list elements. A number must be passed to the second argument of reduce . Can be combined with boolean-returning functions like is , isnt , propertyIs or propertyIsOneOf .

["a", "a", "b"].reduce(countBy(el => el === "a"), 0); // Returns 2
["a", "a", "b"].reduce(countBy(is("a")), 0); // Returns 2

Implementation

const countBy = <T>(func: (el: T) => boolean) => (acc: number, el: T) =>
  acc + (func(el) ? 1 : 0)

duplicates

duplicates: (el: unknown, _: number, list: unknown[]) => boolean

Use with: filter

Returns duplicates

[1, 1, 1, 2].filter(duplicates); // Returns [1, 1, 1]

Implementation

const duplicates = duplicatesBy(el => el)

duplicatesBy

duplicatesBy: <T>(func: (el: T) => unknown) => (el: T, _: number, list: T[]) => boolean

Use with: filter

Returns all duplicates compared by func(element)

[{ a: 1 }, { a : 1 }, { a: 2 }].filter(duplicatesBy(el => el.a)); // Returns [{ a: 1 }, { a: 1 }]

Implementation

const duplicatesBy = <T>(func: (el: T) => unknown) => (
  el: T,
  _: number,
  list: T[]
) => numberOfOccurencesBy(list, el, func) > 1

duplicatesByProperty

duplicatesByProperty: <TObject extends object, TKey extends keyof TObject>(key: TKey) => (el: TObject, _: number, list: TObject[]) => boolean

Use with: filter

Returns duplicates compared by element[key]

[{ a: 1 }, { a: 1 }].filter(duplicatesByProperty('a')); // Return [{ a: 1 }, { a: 1 }]

Implementation

const duplicatesByProperty = <
  TObject extends object,
  TKey extends keyof TObject
>(
  key: TKey
) => duplicatesBy<TObject>(get(key))

exclude

exclude: <T>(list: T[]) => (el: T) => boolean

Use with: filter

Removes the provided elements from the list

[1, 2, 3, 4].filter(exclude([1, 2])); // Returns [3, 4]

Implementation

const exclude = <T>(list: T[]) => (el: T) =>
  findIndex(list, a => a === el) === -1

excludeBy

excludeBy: <T>(func: (el: T) => unknown, list: T[]) => (el: T) => boolean

Use with: filter

Removes the provided elements from the list compared by running func on elements in both lists

[{ a: 1 }, { a: 2 }, { a: 3 }, { a: 4 }]
  .filter(excludeBy(el => el.a, [{ a: 1 }, { a: 2 }]));
  // Returns [{ a: 3 }, { a: 4 }]

Implementation

const excludeBy = <T>(func: (el: T) => unknown, list: T[]) => (el: T) =>
  findIndex(list, a => func(a) === func(el)) === -1

excludeByProperty

excludeByProperty: <TObject extends object, TKey extends keyof TObject>(key: TKey, list: TObject[]) => (el: TObject) => boolean

Use with: filter

Removes the provided elements from the list compared at key

[{ a: 1 }, { a: 2 }, { a: 3 }, { a: 4 }]
  .filter(excludeByProperty('a', [{ a: 1 }, { a: 2 }]));
  // Returns [{ a: 3 }, { a: 4 }]

Implementation

const excludeByProperty = <
  TObject extends object,
  TKey extends keyof TObject
>(
  key: TKey,
  list: TObject[]
) => excludeBy(get(key), list)

get

get: {
  <TObject extends object, TKey1 extends keyof TObject, TKey2 extends keyof TObject[TKey1], TKey3 extends keyof TObject[TKey1][TKey2]>(key1: TKey1, key2: TKey2, key3: TKey3): (obj: TObject) => TObject[TKey1][TKey2][TKey3];
  <TObject extends object, TKey1 extends keyof TObject, TKey2 extends keyof TObject[TKey1]>(key1...;
}

Use with map or filter

Returns element[key] (can also be an array index). Supports up to three keys of depth.

[{ a: 1 }, { a: 2 }].map(get('a')); // Returns [1, 2]
[["a", 1], ["a", 2]].map(get(1)); // Returns [1, 2]
[{ a: { b: { c: 1 } } }].map(get('a', 'b', 'c')); // Returns [1]

Implementation

export function get<
  TObject extends object,
  TKey1 extends keyof TObject,
  TKey2 extends keyof TObject[TKey1],
  TKey3 extends keyof TObject[TKey1][TKey2]
>(key1: TKey1, key2?: TKey2, key3?: TKey3) {
  return (obj: TObject) => {
    if (key3 && key2)
      return obj && obj[key1] && obj[key1][key2] && obj[key1][key2][key3];
    if (key2) return obj && obj[key1] && obj[key1][key2];
    return obj && obj[key1];
  };
}

groupBy

groupBy: <K extends string, V>(func: (el: V) => K | undefined) => (acc: Record<K, V[]>, el: V) => Record<K, V[]>

Use with: reduce

Given a key-returning function, returns an object of lists of elements. A second argument must be passed to reduce . For javascript an empty object is enough. For typescript an object with properties or a type cast is required.

[{ age: 10 }, { age: 80 }].reduce(
  groupBy(el => (el.age > 30 ? "old" : "young")),
  { old: [], young: [] }
); // Returns { old: [{ age: 80 }], young: [{ age: 10 }]}

Implementation

const groupBy = <K extends string, V>(
  func: (el: V) => K | undefined
) => (acc: Record<K, V[]>, el: V): Record<K, V[]> => {
  const groupName = func(el);
  if (!groupName) return acc;
  const group: V[] = acc[groupName] || [];
  return Object.assign({}, acc, { [groupName]: group.concat(el) });
}

groupByProperty

groupByProperty: <K extends keyof V, V extends { [key: string]: any; }>(key: K) => (acc: Record<V[K], V[]>, el: V) => Record<V[K], V[]>

Use with: reduce

Given a property name, returns an object of lists of elements, grouped by the values for that property. A second argument must be passed to reduce . For javascript an empty object is enough. For typescript an object with properties or a type cast is required.

[{ name: "Jane" }, { name: "John" }].reduce(
  groupByProperty("name"),
  {}
); // Returns { Jane: [{ name: "Jane" }], John: [{ name: "John" }] }

Implementation

const groupByProperty = <
  K extends keyof V,
  V extends { [key: string]: any }
>(
  key: K
) => (acc: Record<V[K], V[]>, el: V): Record<V[K], V[]> => {
  const groupName = el[key];
  if (!groupName) return acc;
  const group: V[] = acc[groupName] || [];
  return Object.assign({}, acc, { [groupName]: group.concat(el) });
}

intersection

intersection: <T>(list: T[]) => (el: T) => boolean

Use with: filter

Returns a list of elements that are present in both lists

[1, 2, 3].filter(intersection([2, 3, 4])); // Returns [2, 3]

Implementation

const intersection = <T>(list: T[]) => (el: T) =>
  findIndex(list, a => a === el) !== -1

intersectionBy

intersectionBy: <T>(func: (el: T) => unknown, list: T[]) => (el: T) => boolean

Use with: filter

Returns a list of elements that are present in both lists compared by running func on elements in both lists

[{ a: 1 }, { a: 2 }, { a: 3 }]
  .filter(intersectionBy(el => el.a, [{ a: 2 }, { a: 3 }, { a: 4 }]));
  // Returns [{ a: 2 }, { a: 3 }]

Implementation

const intersectionBy = <T>(func: (el: T) => unknown, list: T[]) => (
  el: T
) => findIndex(list, a => func(a) === func(el)) !== -1

intersectionByProperty

intersectionByProperty: <TObject extends object, TKey extends keyof TObject>(key: TKey, list: TObject[]) => (el: TObject) => boolean

Use with: filter

Returns a list of elements that are present in both lists compared at key

[{ a: 1 }, { a: 2 }, { a: 3 }]
  .filter(intersectionByProperty("a", [{ a: 2 }, { a: 3 }, { a: 4 }]));
  // Returns [{ a: 2 }, { a: 3 }]

Implementation

const intersectionByProperty = <
  TObject extends object,
  TKey extends keyof TObject
>(
  key: TKey,
  list: TObject[]
) => intersectionBy(get(key), list)

is

is: <T>(value: T) => (el: T) => boolean

Use with: find , filter

Returns true for elements that are equal to value

[1,2,3].find(is(1)); // Returns 1
[1,1,2].filter(is(1)); // Returns [1, 1]

Implementation

const is = <T>(value: T) => (el: T) => el === value

isBy

isBy: <T, U>(func: (el: T) => U, value: U) => (el: T) => boolean

Use with: find , filter

Returns true for elements where func(element) equals value

[{ a: 1 }, { a: 2 }].find(isBy(el => el.a, 2)); // Returns { a: 2 }
[{ a: 1 }, { a: 2 }].filter(isBy(el => el.a, 2)); // Returns [{ a: 2 }]

Implementation

const isBy = <T, U>(func: (el: T) => U, value: U) => (el: T) =>
  func(el) === value

isDefined

isDefined: <T>(x: T | undefined) => x is T

Use with: filter

Removes elements that are undefined

[1, undefined, 2].filter(isDefined); // Returns [1, 2]

Implementation

const isDefined = <T>(x: T | undefined): x is T =>
  typeof x !== "undefined"

isOneOf

isOneOf: <T>(list: T[]) => (el: T) => boolean

Use with: find , filter

Alias for intersection . Returns true for elements that exist in the provided list

[1,1,2,2,3].filter(isOneOf([2,3])); // Returns [2, 2, 3]

Implementation

const isOneOf = intersection

isOneOfBy

isOneOfBy: <T, U>(func: (el: T) => U, list: U[]) => (el: T) => boolean

Use with: find , filter

Returns true for elements where func(element) exists in list

[{ a: 1 }, { a: 2 }, { a: 3 }].find(isOneOfBy(el => el.a, [2, 3]));
// ^ Returns { a: 2 }
[{ a: 1 }, { a: 2 }, { a: 3 }].filter(isOneOfBy(el => el.a, [2, 3]));
// ^ Returns [{ a: 2 }, { a: 3 }]

Implementation

const isOneOfBy = <T, U>(func: (el: T) => U, list: U[]) => (el: T) =>
  findIndex(list, a => a === func(el)) !== -1

isnt

isnt: <T>(value: T) => (el: T) => boolean

Use with: find , filter

Returns true for elements that are not equal to value

[1,2,3].find(isnt(1)); // Returns 2
[1,2,2].filter(isnt(1)); // Returns [2,2]

Implementation

const isnt = <T>(value: T) => (el: T) => el !== value

isntBy

isntBy: <T, U>(func: (el: T) => U, value: U) => (el: T) => boolean

Use with: find , filter

Returns true for elements where func(element) does not equal value

[{ a: 1 }, { a: 2 }].find(isntBy(el => el.a, 2)); // Returns { a: 1 }
[{ a: 1 }, { a: 2 }].filter(isntBy(el => el.a, 2)); // Returns [{ a: 1 }]

Implementation

const isntBy = <T, U>(func: (el: T) => U, value: U) => (el: T) =>
  func(el) !== value

isntOneOf

isntOneOf: <T>(list: T[]) => (el: T) => boolean

Use with: find , filter

Alias for exclude . Returns true for elements that do not exist in the provided list

[1,1,2,2,3].filter(isntOneOf([2,3])); // Returns [1, 1]

Implementation

const isntOneOf = exclude

isntOneOfBy

isntOneOfBy: <T, U>(func: (el: T) => U, list: U[]) => (el: T) => boolean

Use with: find , filter

Returns true for elements where func(element) exists in list

[{ a: 1 }, { a: 2 }, { a: 3 }].find(isntOneOfBy(el => el.a, [2, 3]));
// ^ Returns { a: 1 }
[{ a: 1 }, { a: 2 }, { a: 3 }].filter(isntOneOfBy(el => el.a, [2, 3]));
// ^ Returns [{ a: 1 }]

Implementation

const isntOneOfBy = <T, U>(func: (el: T) => U, list: U[]) => (el: T) =>
  findIndex(list, a => a === func(el)) === -1

max

max: (acc: number, el: number) => number

Use with: reduce

Returns the largest value in the list

[1,2,3,4].reduce(max); // Returns 4

Implementation

const max = (acc: number, el: number) => Math.max(acc, el)

maxBy

maxBy: <T>(func: (el: T) => number) => (acc: T, el: T) => T

Use with: reduce

Returns the largest element by comparing func(element)

[{ a: 1 }, { a: 2 }, { a: 3 }].reduce(maxBy(el => el.a)); // Returns { a: 3 }

Implementation

const maxBy = <T>(func: (el: T) => number) => (acc: T, el: T) =>
  func(el) > func(acc) ? el : acc

maxByProperty

maxByProperty: <TObject extends object, TKey extends keyof TObject>(key: TKey) => (acc: TObject, el: TObject) => TObject

Use with: reduce

Returns the largest element by comparing element[key]

[{ a: 1 }, { a: 2 }, { a: 3 }].reduce(maxByProperty("a")); // Returns { a: 3 }

Implementation

const maxByProperty = <
  TObject extends object,
  TKey extends keyof TObject
>(
  key: TKey
) => (acc: TObject, el: TObject) => (el[key] > acc[key] ? el : acc)

min

min: (acc: number, el: number) => number

Use with: reduce

Returns the smallest value in the list

[1,2,3,4].reduce(min); // Returns 1

Implementation

const min = (acc: number, el: number) => Math.min(acc, el)

minBy

minBy: <T>(func: (el: T) => number) => (acc: T, el: T) => T

Use with: reduce

Returns the smallest element by comparing func(element)

[{ a: 1 }, { a: 2 }, { a: 3 }].reduce(minBy(el => el.a)); // Returns { a: 1 }

Implementation

const minBy = <T>(func: (el: T) => number) => (acc: T, el: T) =>
  func(el) < func(acc) ? el : acc

minByProperty

minByProperty: <TObject extends object, TKey extends keyof TObject>(key: TKey) => (acc: TObject, el: TObject) => TObject

Use with: reduce

Returns the smallest element by comparing element[key]

[{ a: 1 }, { a: 2 }, { a: 3 }].reduce(minByProperty("a")); // Returns { a: 1 }

Implementation

const minByProperty = <
  TObject extends object,
  TKey extends keyof TObject
>(
  key: TKey
) => (acc: TObject, el: TObject) => (el[key] < acc[key] ? el : acc)

or

or: <T>(fallback: T) => (x: T | undefined) => T

Use with: map

Replaces list elements that are undefined with fallback

[1, undefined, 2].map(or(0)); // Returns [1, 0, 2]

Implementation

const or = <T>(fallback: T) => (x: T | undefined): T =>
  isDefined(x) ? x : fallback

partition

partition: <T>(func: (el: T) => boolean) => (acc: T[][], el: T) => T[][]

Use with: reduce

Splits the input list into two lists. The first list contains elements for which the given function returned true , the second contains elements for which the function returned false .

[{ age: 10 }, { age: 80 }].reduce(partition(el => el.age > 30), []);
// Returns [[{ age: 80 }], [{ age: 10 }]]

Implementation

const partition = <T>(func: (el: T) => boolean) => (
  acc: T[][],
  el: T
) => {
  const a0 = acc[0] || [],
    a1 = acc[1] || [];
  return func(el) ? [a0.concat(el), a1] : [a0, a1.concat(el)];
}

propertyIs

propertyIs: <TObject extends object, TKey extends keyof TObject>(key: TKey, value: TObject[TKey]) => (el: TObject) => boolean

Use with: find , filter

Returns true for elements where element[key] equals value

[{ a: 1 }, { a: 2 }].find(propertyIs("a", 2)); // Returns { a: 2 }
[{ a: 1 }, { a: 2 }].filter(propertyIs("a", 2)) // Returns [{ a: 2 }]

Implementation

const propertyIs = <TObject extends object, TKey extends keyof TObject>(
  key: TKey,
  value: TObject[TKey]
) => isBy(get(key), value)

propertyIsOneOf

propertyIsOneOf: <TObject extends object, TKey extends keyof TObject>(key: TKey, list: TObject[TKey][]) => (el: TObject) => boolean

Use with: find , filter

Returns true for elements where element[key] exists in list

[{ a: 1 }, { a: 2 }, { a: 3 }].find(propertyIsOneOf("a", [2, 3]));
// ^ Returns { a: 2 }
[{ a: 1 }, { a: 2 }, { a: 3 }].filter(propertyIsOneOf("a", [2, 3]));
// ^ Returns [{ a: 2 }, { a: 3 }]

Implementation

const propertyIsOneOf = <
  TObject extends object,
  TKey extends keyof TObject
>(
  key: TKey,
  list: TObject[TKey][]
) => isOneOfBy(get(key), list)

propertyIsnt

propertyIsnt: <TObject extends object, TKey extends keyof TObject>(key: TKey, value: TObject[TKey]) => (el: TObject) => boolean

Use with: find , filter

Returns true for elements where element[key] does not equal value

[{ a: 1 }, { a: 2 }].find(propertyIsnt("a", 2)); // Returns { a: 1 }
[{ a: 1 }, { a: 2 }].filter(propertyIsnt("a", 2)); // Returns [{ a: 1 }]

Implementation

const propertyIsnt = <
  TObject extends object,
  TKey extends keyof TObject
>(
  key: TKey,
  value: TObject[TKey]
) => isntBy(get(key), value)

propertyIsntOneOf

propertyIsntOneOf: <TObject extends object, TKey extends keyof TObject>(key: TKey, list: TObject[TKey][]) => (el: TObject) => boolean

Use with: find , filter

Returns true for elements where element[key] exists in list

[{ a: 1 }, { a: 2 }, { a: 3 }].find(propertyIsntOneOf("a", [2, 3]));
// ^ Returns { a: 1 }
[{ a: 1 }, { a: 2 }, { a: 3 }].filter(propertyIsntOneOf("a", [2, 3]));
// ^ Returns [{ a: 1 }]

Implementation

const propertyIsntOneOf = <
  TObject extends object,
  TKey extends keyof TObject
>(
  key: TKey,
  list: TObject[TKey][]
) => isntOneOfBy(get(key), list)

sum

sum: (acc: number, element: number) => number

Use with: reduce

Sum a list of numbers

[1, 2, 3].reduce(sum); // Returns 6

Implementation

const sum = (acc: number, element: number) => acc + element

sumBy

sumBy: {
  <T>(func: (el: T) => number): (acc: number, el: T) => number;
  <T>(func: (el: number) => number): (acc: number, el: number) => number;
}

Use with: reduce

Sums the values by applying func to elements. If the list elements aren't numbers, a number must be passed as the second argument to reduce .

[{ a: 1 }, { a: 2 }].reduce(sumBy(el => el.a), 0); // Returns 3
[1.5, 2.5].reduce(sumBy(Math.floor)); // Returns 3

Implementation

export function sumBy<T>(func: (el: T | number) => number) {
  return (acc: number, el: T | number) =>
    typeof el === "number" ? func(acc) + func(el) : acc + func(el);
}

sumByProperty

sumByProperty: <TObject extends { [key: string]: number; }, TKey extends keyof TObject>(key: TKey) => (acc: number, el: TObject) => number

Use with: reduce

Sums the values of element[key] for all elements. A number must be passed to the second argument of reduce .

[{ a: 1 }, { a: 2 }].reduce(sumByProperty('a'), 0); // Returns 3

Implementation

const sumByProperty = <
  TObject extends { [key: string]: number },
  TKey extends keyof TObject
>(
  key: TKey
) => (acc: number, el: TObject) => acc + el[key]

unique

unique: (el: unknown, index: number, list: unknown[]) => boolean

Use with: filter

Removes duplicates from list

[1,1,1,2].filter(unique); // Returns [1, 2]

Implementation

const unique = uniqueBy(el => el)

uniqueBy

uniqueBy: <T>(func: (el: T) => unknown) => (el: T, index: number, list: T[]) => boolean

Use with: filter

Removes duplicates compared by func(element)

[{ a: 1 }, { a : 1 }].filter(uniqueBy(el => el.a)); // Returns [{ a: 1 }]

Implementation

const uniqueBy = <T>(func: (el: T) => unknown) => (
  el: T,
  index: number,
  list: T[]
) => index === findIndex(list, t => func(t) === func(el))

uniqueByProperty

uniqueByProperty: <TObject extends object, TKey extends keyof TObject>(key: TKey) => (el: TObject, index: number, list: TObject[]) => boolean

Use with: filter

Removes duplicates compared by element[key]

[{ a: 1 }, { a: 1 }].filter(uniqueByProperty('a')); // Return [{ a: 1 }]

Implementation

const uniqueByProperty = <
  TObject extends object,
  TKey extends keyof TObject
>(
  key: TKey
) => uniqueBy<TObject>(get(key))

FAQs

Package last updated on 12 Nov 2020

Did you know?

Socket

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Install

Related posts

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc