Skip to main content

Recipes

tip

No recipe for what you're trying to do? File an issue or update the documentation!

How do I group values by a key?

If each key is associated with exactly one value, then you can use a keyed reducer:

import { map, pipe, reduce, toMap } from 'lfi'

console.log(
pipe(
[`sloth`, `lazy`, `sleep`],
// Create an iterable of key-value pairs
map(word => [word, word.length]),
// Collect the key-value pairs into a map
reduce(toMap()),
),
)
//=> Map(3) {
//=> 'sloth' => 5,
//=> 'lazy' => 4,
//=> 'sleep' => 5
//=> }
Playground
warning

If there are multiple key-value pairs with the same key, then only the last key-value pair is preserved.

If each key is associated with one or more values, then you can use toGrouped:

import { map, pipe, reduce, toArray, toGrouped, toMap } from 'lfi'

console.log(
pipe(
[`sloth`, `lazy`, `sleep`],
// Create an iterable of key-value pairs
map(word => [word.length, word]),
// Collect the values by key into a map where each group is an array
reduce(toGrouped(toArray(), toMap())),
),
)
//=> Map(2) {
//=> 5 => [ 'sloth', 'sleep' ],
//=> 4 => [ 'lazy' ]
//=> }
Playground

In both cases you can swap out both toArray and toMap for other reducers to collect the key-value pairs into different data structures.

How do I limit the concurrency of a concur iterable?

You can wrap the async callback you want to limit the concurrency of with limit-concur:

import { asConcur, mapConcur, pipe, reduceConcur, toArray } from 'lfi'
import limitConcur from 'limit-concur'

const API_URL = `https://random-word-form.herokuapp.com/random/adjective`

let pendingRequests = 0
console.log(
await pipe(
asConcur([`strawberry`, `max`, `bitsy`, `tommy`]),
mapConcur(
// At most 2 requests at a time
limitConcur(2, async sloth => {
console.log(++pendingRequests)
const [adjective] = await (await fetch(API_URL)).json()
console.log(--pendingRequests)
return `${adjective} ${sloth}`
}),
),
reduceConcur(toArray()),
),
)
//=> 1
//=> 2
//=> 1
//=> 2
//=> 1
//=> 2
//=> 1
//=> 0
// NOTE: This order may change between runs
//=> [
//=> 'kind strawberry',
//=> 'humble max',
//=> 'great bitsy',
//=> 'beautiful tommy'
//=> ]
Playground

How do I reduce an iterable to more than one result in one pass?

You can use toMultiple:

import { map, pipe, reduce, toCount, toJoin, toMultiple, toSet } from 'lfi'

console.log(
pipe(
[`sloth`, `lazy`, `sleep`],
map(word => word.length),
reduce(toMultiple([toSet(), toCount(), toJoin(`,`)])),
),
)
//=> [
//=> Set(2) { 5, 4 },
//=> 3,
//=> '5,4,5'
//=> ]

console.log(
pipe(
[`sloth`, `lazy`, `sleep`],
map(word => word.length),
reduce(
toMultiple({
set: toSet(),
count: toCount(),
string: toJoin(`,`),
}),
),
),
)
//=> {
//=> set: Set(2) { 5, 4 },
//=> count: 3,
//=> string: '5,4,5'
//=> }
Playground