Leisure
GithubIssue TrackerSponsor
  • Introduction
  • Installation
  • Changelog
  • F.A.Q.
  • API
    • Static Methods
    • Instance Methods
    • Simplex Methods
    • Combinatorial Methods
    • Random Number Generating Methods
Powered by GitBook
On this page
  • map
  • window
  • pairwise
  • isEmpty
  • tap
  • log
  • flat
  • flatMap
  • filter
  • concat
  • interleave
  • interpose
  • distinct
  • distinctBy
  • partitionBy
  • includes
  • find
  • reduce
  • chain
  • some
  • every
  • take
  • takeWhile
  • skip
  • skipWhile
  • nth
  • index
  • first
  • zip
  • zipWith
  • zip2
  • zip2With
  • toArray
  • forEach
  • sum
  • sumBy
  • average
  • averageBy
  • frequencies
  • groupBy

Was this helpful?

  1. API

Instance Methods

map

It's map, the most important method in programming! Exactly the same as ES6 map, but lazy.

const sequence: Seq<string> = Seq.infinite().map(num => num.toString())
type map = <U>(fn: (value: T, index: number) => U) => Seq<U>

window

window takes a sequence and groups it into "windows" of a certain length. This works well with infinite sequences where you want to process some number of values at a time.

// Grab numbers in groups of 10.
const sequence: Seq<number[]> = Seq.infinite().window(10)

By default, only triggers chained responses when the window fills, guaranteeing the window is the exact size expect. Set allowPartialWindow to false to allow the trailing edge of a sequence to not be divisible by the window size.

// Gives: [0, 1, 2] -> [3, 4, 5] -> [6, 7, 8] -> [9, 10]
const sequence: Seq<number> = Seq.range(0, 10).window(3)
type window = (size: number, allowPartialWindow = true) => Seq<T[]>

pairwise

Works like window, makes the window size 2. Groups a sequence as alternating pairs. Useful for processing data which alternates Map keys and values.

const sequence: Seq<[string, number]> = Seq.fromArray(["a", 1, "b", 2])
type pairwise = () => Seq<[T, T]>

isEmpty

Ask whether a sequence is empty.

const anythingInThere: boolean = Seq.empty().isEmpty()
type isEmpty = () => boolean

tap

tap lets you run side-effect generating functions on a sequence. Allows you to "tap in to" a data flow. Very useful for logging and debugging what values are flowing through the chain at a given location.

const sequence: Seq<number> = Seq.infinite().tap(num => console.log(num))
type tap = (fn: (value: T, index: number) => void) => Seq<T>

log

log provides the most common use-case for `tap. Add this to a sequence chain to log each value that passes through it.

const sequence: Seq<number> = Seq.infinite().log()
type log = () => Seq<T>

flat

Given a sequence where each item in an array of items, flatten all those arrays into a single flat sequence of values.

type Person = { name: string; friends: Person[] }

const sequence: Seq<Friend> = Seq.fromArray([person1, person2])
  .map(person => person.friends)
  .flat()
type flat = <U>(this: Seq<U[]>) => Seq<U>

flatMap

flatMap is used when mapping a list to each items related items. For example, if you wanted to map from a list of people to each persons list of friends. Despite each mapping function returning an array, the final output is a flatten array of all the results concattenated.

Similar to [].map().flat(), but in leisure the item mappings won't execute until enough of the resulting values have been realized to trigger each map.

type Person = { name: string; friends: Person[] }

const sequence: Seq<Friend> = Seq.fromArray([person1, person2]).flatMap(
  person => person.friends,
)
type flatMap = <U>(fn: (value: T, index: number) => U[]) => Seq<U>

filter

Runs a predicate function on each item in a sequence to produce a new sequence where only the values which responded with true remain.

// Create a sequence of only even numbers.
const sequence: Seq<number> = Seq.infinite().filter(num => num % 2 === 0)
type filter = (fn: (value: T, index: number) => unknown) => Seq<T>

concat

Combines the current sequence with 1 or more additional sequences.

const sequence: Seq<number> = Seq.fromArray([0, 1]).concat(
  Seq.fromArray([2, 3]),
  Seq.fromArray([4, 5]),
)
type concat = (...tail: Array<Seq<T>>) => Seq<T>

interleave

Takes 1 or more sequences and creates a new sequence built by pulling the next value from each of the sequences in order.

// Builds: a -> 1 -> b -> 2 -> c -> 3
const sequence: Seq<string | number> = Seq.fromArray([
  "a",
  "b",
  "c",
]).interleave(Seq.range(1, 3))
type interleave = (...tail: Array<Seq<T>>) => Seq<T>

interpose

Given a sequence, place a value between each value of the original sequence. Useful for adding punctuation between strings.

// Builds: Apples -> , -> Oranges -> , -> Bananas
const sequence: Seq<string> = Seq.fromArray([
  "Apples",
  "Oranges",
  "Bananas",
]).interpose(", ")

console.log(sequence.toArray().join(""))
type interpose = (separator: T) => Seq<T>

distinct

Given a sequence, only forwards the values which have no already been seen. Very similar to lodash's uniq method.

// Builds: 1 -> 2 -> 3 -> 4
const sequence: Seq<number> = Seq.fromArray([1, 2, 3, 2, 1, 4]).distinct()
type distinct = () => Seq<T>

distinctBy

Same as distinct, but allows a function to describe on what value the sequence should be unique.

// Builds: { firstName: "A", lastName: "Z" } ->
//         { firstName: "B", lastName: "Y" } ->
//         { firstName: "C", lastName: "W" }
type Person = { firstName: string; lastName: string }
const sequence: Seq<Person> = Seq.fromArray([
  { firstName: "A", lastName: "Z" },
  { firstName: "B", lastName: "Y" },
  { firstName: "A", lastName: "X" },
  { firstName: "C", lastName: "W" },
]).distinctBy(person => person.firstName)
type distinctBy = <U>(fn: (value: T) => U) => Seq<T>

partitionBy

Given a sequence, splits the values into two separate sequences. One represents the values where the partition function is true and the other for false.

const [isEven, isOdd] = Seq.infinite().partitionBy(num => num % 2 === 0)
type partition = (fn: (value: T, index: number) => unknown) => [Seq<T>, Seq<T>]

includes

Lazily checks if the sequence includes a value.

const doesItInclude = Seq.infinite().includes(10)
type includes = (value: T) => boolean

find

Lazily searches for a value that matches the predicate.

// Returns 11
const gtTen = Seq.infinite().find(num => num > 10)
type find = (fn: (value: T, index: number) => unknown) => T | undefined

reduce

// Returns 0 + 1 + 2 + 3 + 4 = 10
const sum = Seq.infinite()
  .take(5)
  .reduce((sum, num) => sum + num)
type reduce = <A>(fn: (sum: A, value: T, index: number) => A, initial: A) => A

chain

This method is helpful for chaining. Shocking, I know. Let's you "map" the entire sequence in a chain, rather than per-each-item. Allows adding arbitrary sequence helpers and methods to chain, even if they are written in user-land and not on the Seq prototype.

// Same as `Seq.interpose(Seq.infinite(), Seq.infinite())`
const sequence = Seq.infinite().chain(seq => seq.interpose(Seq.infinite()))
type chain = <U>(fn: (value: Seq<T>) => U) => U

some

// Find the first even random number.
const areAnyEven = Seq.random()
  .map(num => Math.round(num * 1000))
  .some(num => num % 2 === 0)
type some = (fn: (value: T, index: number) => unknown) => boolean

every

// Fails fast if there are negative numbers
const areAllPositive = Seq.random()
  .map(num => Math.round(num * 1000) - 500)
  .every(num => num > 0)
type every = (fn: (value: T, index: number) => unknown) => boolean

take

Given a sequence of unknown length, create a sub sequence of just the first X number of items.

// Grabs 0 -> 1 -> 2 -> 3 -> 4
const firstFive = Seq.infinite().take(5)
type take = (num: number) => Seq<T>

takeWhile

Given a sequence of unknown length, create a sub sequence of as many items in a row that satisfy the predicate.

// Gives 0 -> 1 -> 2 -> 3 -> 4
const lessThanFive = Seq.infinite().takeWhile(num => num < 5)
type takeWhile = (fn: (value: T, index: number) => unknown) => Seq<T>

skip

Given a sequence of unknown length, skips the first X number of items.

// Gives 5 -> 6 -> 7 -> 8 -> 9
const secondFive = Seq.infinite().skip(5).take(5)
type skip = (num: number) => Seq<T>

skipWhile

Given a sequence of unknown length, skip as many items in a row that satisfy the predicate.

// Gives 5 -> 6 -> 7 -> 8 -> 9
const greaterThanFive = Seq.infinite()
  .skipWhile(num => num < 5)
  .take(5)
type skipWhile = (fn: (value: T, index: number) => unknown) => Seq<T>

nth

Returns the nth item. Items are 1-indexed.

const thirdItem = Seq.infinite().nth(3)
type nth = (i: number) => T | undefined

index

Returns the index item. Items are 0-indexed.

const fourthItem = Seq.infinite().index(3)
type nth = (i: number) => T | undefined

first

Gets the first value in the sequence.

const fifth = Seq.infinite().skip(4).first()
type first = () => T | undefined

zip

Lazily combines a second sequence with this current one to produce a tuple with the current step in each of the two positions. Useful for zipping a sequence of keys with a sequence of values, before converting to a Map of key to value.

const seq2 = Seq.range(0, 3)

// Gives: ["zero", 0] -> ["one", 1] -> ["two", 2] -> ["three", 3]
const sequence: Seq<[string, number]> = Seq.fromArray([
  "zero",
  "one",
  "two",
  "three",
]).zip(seq2)
type zip<T2> = (seq2: Seq<T2>) => Seq<[T | undefined, T2 | undefined]>

zipWith

Takes a second sequence and lazily combines it to produce an arbitrary value by mapping the current value of the two positions through a user-supplied function. Useful for table (row/col) math.

const seq2 = Seq.repeat(2)

// Gives: 0 -> 2 -> 4 -> 6
const sequence: Seq<number> = Seq.range(0, 3).zipWith(
  ([num, multiplier]) => num * multiplier,
  seq2,
)
type zip2With = <T2, T3, T4>(
  fn: (
    [result1, result2, result3]:
      | [T, T2, T3]
      | [T, undefined, undefined]
      | [T, T2, undefined]
      | [T, undefined, T3]
      | [undefined, T2, undefined]
      | [undefined, T2, T3]
      | [undefined, undefined, T3],
    index: number,
  ) => T4,
  seq2: Seq<T2>,
  seq3: Seq<T3>,
) => Seq<T4>

zip2

Takes two sequences and lazily combines them with this one to produce a 3-tuple with the current step in each of the three positions.

const seq2 = Seq.range(0, 3)
const seq3 = Seq.range(3, 0)

// Gives: ["zero", 0, 3] -> ["one", 1, 2] -> ["two", 2, 1] -> ["three", 3, 0]
const sequence: Seq<[string, number]> = Seq.fromArray([
  "zero",
  "one",
  "two",
  "three",
]).zip2(seq2, seq3)
type zip2 = <T2, T3>(
  seq2: Seq<T2>,
  seq3: Seq<T3>,
) => Seq<[T | undefined, T2 | undefined, T3 | undefined]>

zip2With

Takes two sequences and lazily combine them with this sequence to produce an arbitrary value by mapping the current value of the three positions through a user-supplied function.

const seq2 = Seq.repeat(2)
const seq3 = Seq.repeat(1)

// Gives: 0 -> 2 -> 4 -> 6
const sequence: Seq<number> = Seq.range(0, 3).zip2With(
  ([num, multiplier, divisor]) => (num * multiplier) / divisor,
  seq2,
  seq3,
)
type zip2With = <T2, T3, T4>(
  fn: (
    [result1, result2, result3]:
      | [T, T2, T3]
      | [T, undefined, undefined]
      | [T, T2, undefined]
      | [T, undefined, T3]
      | [undefined, T2, undefined]
      | [undefined, T2, T3]
      | [undefined, undefined, T3],
    index: number,
  ) => T4,
  seq2: Seq<T2>,
  seq3: Seq<T3>,
) => Seq<T4>

toArray

Converts the sequence to a real JavaScript array. Realizes the entire sequence.

const lessThanTen = Seq.infinite().take(10).toArray()
type toArray = () => T[]

forEach

type forEach = (fn: (value: T, index: number) => void) => void

sum

Given a sequence of numbers, adds them all together. This realizes the entire sequence.

// Returns 0 + 1 + 2 + 3 + 4 = 10
const sum = Seq.infinite().take(5).sum()
type sum = (this: Seq<number>) => number

sumBy

Given a sequence of arbitrary data, adds together the result of the mapping function. This realizes the entire sequence.

// Returns 0 + 1 + 2 + 3 + 4 = 10
const sum = Seq.fromArray([
  { balance: 0 },
  { balance: 1 },
  { balance: 2 },
  { balance: 3 },
  { balance: 4 },
]).sumBy(user => user.balance)

</div>

<div data-gb-custom-block data-tag="tab" data-title='Type Definition'>

```typescript
type sumBy = (fn: (value: T) => number) => number;

average

Given a sequence of numbers, averages them all together. Tise realizes the entire sequence.

// Returns (0 + 1 + 2 + 3 + 4) / 5 = 2
const sum = Seq.infinite().take(5).average()
type average = (this: Seq<number>) => number

averageBy

Given a sequence of arbitrary data, averages together the result of the mapping function. This realizes the entire sequence.

// Returns (0 + 1 + 2 + 3 + 4) / 5 = 2
const sum = Seq.fromArray([
  { balance: 0 },
  { balance: 1 },
  { balance: 2 },
  { balance: 3 },
  { balance: 4 },
]).averageBy(user => user.balance)
type averageBy = (fn: (value: T) => number) => number

frequencies

Given a non-infinite sequence, return a Map which counts the occurances of each unique value. This realizes the entire sequence.

// Returns a Map of numbers from 0->100 and how many times they randomly occured in this set of 500.
const freq = Seq.random()
  .map(num => Math.round(num * 100))
  .take(500)
  .frequencies()
type frequencies = () => Map<T, number>

groupBy

Group a sequence by the return of a mapping function. This realizes the entire sequence.

// Random generates 1000 years between 0-2000 and
// groups them by decade.
const groupedByDecade = Seq.random()
  .map(num => Math.round(num * 2000))
  .take(100)
  .groupBy(year => Math.round(year / 10))
type groupBy = <U>(fn: (item: T) => U) => Map<U, T[]>
PreviousStatic MethodsNextSimplex Methods

Last updated 2 years ago

Was this helpful?

Works just like Array.prototype.flat.

Works just like Array.prototype.flatMap.

Exactly the same as Array.prototype.filter, but lazy. .

Exactly the same as Array.prototype.concat, but lazy. .

Exactly the same as Array.prototype.includes, but lazy. .

Exactly the same as Array.prototype.find, but lazy. .

Exactly the same as Array.prototype.reduce. . This causes a full realization of the data. Not lazy.

Exactly the same as Array.prototype.some, but lazy. .

Exactly the same as Array.prototype.every, but lazy. .

Works just like Array.prototype.forEach. . Realizes the full sequence.

See more here.
See more here.
See more here
See more here
See more here
See more here
See more here
See more here
See more here
See more here