@pacote/linked-list
Advanced tools
Comparing version 0.1.0 to 0.2.0
@@ -6,2 +6,8 @@ # Change Log | ||
# [0.2.0](https://github.com/PacoteJS/pacote/compare/@pacote/linked-list@0.1.0...@pacote/linked-list@0.2.0) (2020-09-11) | ||
### Features | ||
- 🎸 adds flatMap function ([f23dedc](https://github.com/PacoteJS/pacote/commit/f23dedce0952205cdd1cbb7d5bdc4561be379c37)) | ||
# 0.1.0 (2020-09-05) | ||
@@ -8,0 +14,0 @@ |
@@ -5,6 +5,6 @@ import { Option } from '@pacote/option'; | ||
export declare type LinkedList<T> = Cons<T> | Empty; | ||
declare type FunctionArgs<T> = [value: T, index: number, collection: LinkedList<T>]; | ||
declare type MapFunction<T, R> = (...args: FunctionArgs<T>) => R; | ||
export declare type PredicateFunction<T> = MapFunction<T, boolean>; | ||
declare type ReduceFn<T, R> = (acc: R, ...args: FunctionArgs<T>) => R; | ||
declare type CallbackArgs<T> = [value: T, index: number, collection: LinkedList<T>]; | ||
declare type MapCallback<T, R> = (...args: CallbackArgs<T>) => R; | ||
declare type ReduceCallback<T, R> = (acc: R, ...args: CallbackArgs<T>) => R; | ||
export declare type PredicateFunction<T> = MapCallback<T, boolean>; | ||
export declare function car<T>(cons: Cons<T>): T; | ||
@@ -16,5 +16,6 @@ export declare function cdr<T>(cons: Cons<T> | Empty): Cons<T> | Empty; | ||
export declare function append<T>(value: T, list: LinkedList<T>): LinkedList<T>; | ||
export declare function reduce<T, R>(reducer: ReduceFn<T, R>, initial: R, list: LinkedList<T>): R; | ||
export declare function reduceRight<T, R>(reducer: ReduceFn<T, R>, initial: R, list: LinkedList<T>): R; | ||
export declare function map<T, R>(mapper: MapFunction<T, R>, list: LinkedList<T>): LinkedList<R>; | ||
export declare function reduce<T, R>(callback: ReduceCallback<T, R>, initial: R, list: LinkedList<T>): R; | ||
export declare function reduceRight<T, R>(callback: ReduceCallback<T, R>, initial: R, list: LinkedList<T>): R; | ||
export declare function map<T, R>(callback: MapCallback<T, R>, list: LinkedList<T>): LinkedList<R>; | ||
export declare function flatMap<T, R>(callback: MapCallback<T, LinkedList<R>>, list: LinkedList<T>): LinkedList<R>; | ||
export declare function filter<T>(predicate: PredicateFunction<T>, list: LinkedList<T>): LinkedList<T>; | ||
@@ -21,0 +22,0 @@ export declare function reverse<T>(list: LinkedList<T>): LinkedList<T>; |
"use strict"; | ||
exports.__esModule = true; | ||
exports.tail = exports.head = exports.concat = exports.length = exports.reverse = exports.filter = exports.map = exports.reduceRight = exports.reduce = exports.append = exports.prepend = exports.isEmpty = exports.emptyList = exports.cdr = exports.car = void 0; | ||
exports.tail = exports.head = exports.concat = exports.length = exports.reverse = exports.filter = exports.flatMap = exports.map = exports.reduceRight = exports.reduce = exports.append = exports.prepend = exports.isEmpty = exports.emptyList = exports.cdr = exports.car = void 0; | ||
var option_1 = require("@pacote/option"); | ||
@@ -29,22 +29,28 @@ function car(cons) { | ||
exports.append = append; | ||
function recursiveReduce(acc, reducer, current, step, index, collection) { | ||
function recursiveReduce(acc, callback, current, step, index, collection) { | ||
return isEmpty(current) | ||
? acc | ||
: recursiveReduce(reducer(acc, car(current), index, collection), reducer, cdr(current), step, index + step, collection); | ||
: recursiveReduce(callback(acc, car(current), index, collection), callback, cdr(current), step, index + step, collection); | ||
} | ||
function reduce(reducer, initial, list) { | ||
return recursiveReduce(initial, reducer, list, 1, 0, list); | ||
function reduce(callback, initial, list) { | ||
return recursiveReduce(initial, callback, list, 1, 0, list); | ||
} | ||
exports.reduce = reduce; | ||
function reduceRight(reducer, initial, list) { | ||
function reduceRight(callback, initial, list) { | ||
var lastIndex = length(list) - 1; | ||
return recursiveReduce(initial, reducer, reverse(list), -1, lastIndex, list); | ||
return recursiveReduce(initial, callback, reverse(list), -1, lastIndex, list); | ||
} | ||
exports.reduceRight = reduceRight; | ||
function map(mapper, list) { | ||
function map(callback, list) { | ||
return reverse(reduce(function (acc, value, index, collection) { | ||
return prepend(mapper(value, index, collection), acc); | ||
return prepend(callback(value, index, collection), acc); | ||
}, emptyList(), list)); | ||
} | ||
exports.map = map; | ||
function flatMap(callback, list) { | ||
return reverse(reduce(function (acc, value, index, collection) { | ||
return concat(reverse(callback(value, index, collection)), acc); | ||
}, emptyList(), list)); | ||
} | ||
exports.flatMap = flatMap; | ||
function filter(predicate, list) { | ||
@@ -51,0 +57,0 @@ return reverse(reduce(function (acc, value, index, collection) { |
@@ -1,2 +0,2 @@ | ||
export { append, cdr as rest, concat, filter, head, isEmpty, length, map, prepend, reduce, reduceRight, reverse, tail, } from './core'; | ||
export { append, cdr as rest, concat, filter, flatMap, head, isEmpty, length, map, prepend, reduce, reduceRight, reverse, tail, } from './core'; | ||
export { every, find, findIndex, get, includes, indexOf, lastIndexOf, some, } from './find'; | ||
@@ -3,0 +3,0 @@ export { listOf, toArray } from './array'; |
@@ -10,3 +10,3 @@ "use strict"; | ||
exports.__esModule = true; | ||
exports.sort = exports.remove = exports.slice = exports.values = exports.keys = exports.entries = exports.toArray = exports.listOf = exports.some = exports.lastIndexOf = exports.indexOf = exports.includes = exports.get = exports.findIndex = exports.find = exports.every = exports.tail = exports.reverse = exports.reduceRight = exports.reduce = exports.prepend = exports.map = exports.length = exports.isEmpty = exports.head = exports.filter = exports.concat = exports.rest = exports.append = void 0; | ||
exports.sort = exports.remove = exports.slice = exports.values = exports.keys = exports.entries = exports.toArray = exports.listOf = exports.some = exports.lastIndexOf = exports.indexOf = exports.includes = exports.get = exports.findIndex = exports.find = exports.every = exports.tail = exports.reverse = exports.reduceRight = exports.reduce = exports.prepend = exports.map = exports.length = exports.isEmpty = exports.head = exports.flatMap = exports.filter = exports.concat = exports.rest = exports.append = void 0; | ||
var core_1 = require("./core"); | ||
@@ -17,2 +17,3 @@ __createBinding(exports, core_1, "append"); | ||
__createBinding(exports, core_1, "filter"); | ||
__createBinding(exports, core_1, "flatMap"); | ||
__createBinding(exports, core_1, "head"); | ||
@@ -19,0 +20,0 @@ __createBinding(exports, core_1, "isEmpty"); |
@@ -5,6 +5,6 @@ import { Option } from '@pacote/option'; | ||
export declare type LinkedList<T> = Cons<T> | Empty; | ||
declare type FunctionArgs<T> = [value: T, index: number, collection: LinkedList<T>]; | ||
declare type MapFunction<T, R> = (...args: FunctionArgs<T>) => R; | ||
export declare type PredicateFunction<T> = MapFunction<T, boolean>; | ||
declare type ReduceFn<T, R> = (acc: R, ...args: FunctionArgs<T>) => R; | ||
declare type CallbackArgs<T> = [value: T, index: number, collection: LinkedList<T>]; | ||
declare type MapCallback<T, R> = (...args: CallbackArgs<T>) => R; | ||
declare type ReduceCallback<T, R> = (acc: R, ...args: CallbackArgs<T>) => R; | ||
export declare type PredicateFunction<T> = MapCallback<T, boolean>; | ||
export declare function car<T>(cons: Cons<T>): T; | ||
@@ -16,5 +16,6 @@ export declare function cdr<T>(cons: Cons<T> | Empty): Cons<T> | Empty; | ||
export declare function append<T>(value: T, list: LinkedList<T>): LinkedList<T>; | ||
export declare function reduce<T, R>(reducer: ReduceFn<T, R>, initial: R, list: LinkedList<T>): R; | ||
export declare function reduceRight<T, R>(reducer: ReduceFn<T, R>, initial: R, list: LinkedList<T>): R; | ||
export declare function map<T, R>(mapper: MapFunction<T, R>, list: LinkedList<T>): LinkedList<R>; | ||
export declare function reduce<T, R>(callback: ReduceCallback<T, R>, initial: R, list: LinkedList<T>): R; | ||
export declare function reduceRight<T, R>(callback: ReduceCallback<T, R>, initial: R, list: LinkedList<T>): R; | ||
export declare function map<T, R>(callback: MapCallback<T, R>, list: LinkedList<T>): LinkedList<R>; | ||
export declare function flatMap<T, R>(callback: MapCallback<T, LinkedList<R>>, list: LinkedList<T>): LinkedList<R>; | ||
export declare function filter<T>(predicate: PredicateFunction<T>, list: LinkedList<T>): LinkedList<T>; | ||
@@ -21,0 +22,0 @@ export declare function reverse<T>(list: LinkedList<T>): LinkedList<T>; |
@@ -20,17 +20,20 @@ import { None, Some } from '@pacote/option'; | ||
} | ||
function recursiveReduce(acc, reducer, current, step, index, collection) { | ||
function recursiveReduce(acc, callback, current, step, index, collection) { | ||
return isEmpty(current) | ||
? acc | ||
: recursiveReduce(reducer(acc, car(current), index, collection), reducer, cdr(current), step, index + step, collection); | ||
: recursiveReduce(callback(acc, car(current), index, collection), callback, cdr(current), step, index + step, collection); | ||
} | ||
export function reduce(reducer, initial, list) { | ||
return recursiveReduce(initial, reducer, list, 1, 0, list); | ||
export function reduce(callback, initial, list) { | ||
return recursiveReduce(initial, callback, list, 1, 0, list); | ||
} | ||
export function reduceRight(reducer, initial, list) { | ||
export function reduceRight(callback, initial, list) { | ||
const lastIndex = length(list) - 1; | ||
return recursiveReduce(initial, reducer, reverse(list), -1, lastIndex, list); | ||
return recursiveReduce(initial, callback, reverse(list), -1, lastIndex, list); | ||
} | ||
export function map(mapper, list) { | ||
return reverse(reduce((acc, value, index, collection) => prepend(mapper(value, index, collection), acc), emptyList(), list)); | ||
export function map(callback, list) { | ||
return reverse(reduce((acc, value, index, collection) => prepend(callback(value, index, collection), acc), emptyList(), list)); | ||
} | ||
export function flatMap(callback, list) { | ||
return reverse(reduce((acc, value, index, collection) => concat(reverse(callback(value, index, collection)), acc), emptyList(), list)); | ||
} | ||
export function filter(predicate, list) { | ||
@@ -37,0 +40,0 @@ return reverse(reduce((acc, value, index, collection) => predicate(value, index, collection) ? prepend(value, acc) : acc, emptyList(), list)); |
@@ -1,2 +0,2 @@ | ||
export { append, cdr as rest, concat, filter, head, isEmpty, length, map, prepend, reduce, reduceRight, reverse, tail, } from './core'; | ||
export { append, cdr as rest, concat, filter, flatMap, head, isEmpty, length, map, prepend, reduce, reduceRight, reverse, tail, } from './core'; | ||
export { every, find, findIndex, get, includes, indexOf, lastIndexOf, some, } from './find'; | ||
@@ -3,0 +3,0 @@ export { listOf, toArray } from './array'; |
@@ -1,2 +0,2 @@ | ||
export { append, cdr as rest, concat, filter, head, isEmpty, length, map, prepend, reduce, reduceRight, reverse, tail, } from './core'; | ||
export { append, cdr as rest, concat, filter, flatMap, head, isEmpty, length, map, prepend, reduce, reduceRight, reverse, tail, } from './core'; | ||
export { every, find, findIndex, get, includes, indexOf, lastIndexOf, some, } from './find'; | ||
@@ -3,0 +3,0 @@ export { listOf, toArray } from './array'; |
{ | ||
"name": "@pacote/linked-list", | ||
"description": "Immutable linked lists.", | ||
"version": "0.1.0", | ||
"version": "0.2.0", | ||
"sideEffects": false, | ||
@@ -39,3 +39,3 @@ "license": "MIT", | ||
}, | ||
"gitHead": "4c4d0ed47596a23b39f35e4f4ba4ff36481d6aa9" | ||
"gitHead": "dd9d67802b3876ccf42faa5d45970af71187eebb" | ||
} |
@@ -78,21 +78,26 @@ # @pacote/linked-list | ||
### `map<T, R>(mapper: (element: T, index: number, collection: LinkedList<T>) => R, list: LinkedList<T>): LinkedList<R>` | ||
### `map<T, R>(callback: (element: T, index: number, collection: LinkedList<T>) => R, list: LinkedList<T>): LinkedList<R>` | ||
`map()` iterates over all items in the provided list and evaluates each element | ||
through the `mapper` function, returning a new list containing the resulting | ||
through the `callback` function, returning a new list containing the resulting | ||
values. | ||
### `reduce<T, R>(reducer: (accumulator: R, element: T, index: number, collection: LinkedList<T>) => R, initial: R, list: LinkedList<T>): R` | ||
### `flatMap<T, R>(callback: (element: T, index: number, collection: LinkedList<T>) => LinkedList<R>, list: LinkedList<T>): LinkedList<R>` | ||
`reduce()` executes the provided `reducer` function on each element of the list, | ||
resulting in a single output value, which gets successively passed to the | ||
`reducer` function in the next execution. | ||
`flatMap()` iterates over all items in the provided list and evaluates each | ||
element through the `callback` function and flattening the result by one level. | ||
The first time the `reducer` function is executed, it receives the `initial` | ||
### `reduce<T, R>(callback: (accumulator: R, element: T, index: number, collection: LinkedList<T>) => R, initial: R, list: LinkedList<T>): R` | ||
`reduce()` executes the provided `callback` function on each element of the | ||
list, resulting in a single output value, which gets successively passed to the | ||
`callback` function in the next execution. | ||
The first time the `callback` function is executed, it receives the `initial` | ||
value. | ||
The result of the last execution of the `reducer` function is returned by | ||
The result of the last execution of the `callback` function is returned by | ||
`reduce()`. | ||
### `reduceRight<T, R>(reducer: (accumulator: R, element: T, index: number, collection: LinkedList<T>) => R, initial: R, list: LinkedList<T>): R` | ||
### `reduceRight<T, R>(callback: (accumulator: R, element: T, index: number, collection: LinkedList<T>) => R, initial: R, list: LinkedList<T>): R` | ||
@@ -99,0 +104,0 @@ `reduceRight()` works like `reduce()`, but the list is iterated starting at the |
@@ -7,6 +7,6 @@ import { None, Option, Some } from '@pacote/option' | ||
type FunctionArgs<T> = [value: T, index: number, collection: LinkedList<T>] | ||
type MapFunction<T, R> = (...args: FunctionArgs<T>) => R | ||
export type PredicateFunction<T> = MapFunction<T, boolean> | ||
type ReduceFn<T, R> = (acc: R, ...args: FunctionArgs<T>) => R | ||
type CallbackArgs<T> = [value: T, index: number, collection: LinkedList<T>] | ||
type MapCallback<T, R> = (...args: CallbackArgs<T>) => R | ||
type ReduceCallback<T, R> = (acc: R, ...args: CallbackArgs<T>) => R | ||
export type PredicateFunction<T> = MapCallback<T, boolean> | ||
@@ -39,3 +39,3 @@ export function car<T>(cons: Cons<T>): T { | ||
acc: R, | ||
reducer: ReduceFn<T, R>, | ||
callback: ReduceCallback<T, R>, | ||
current: LinkedList<T>, | ||
@@ -49,4 +49,4 @@ step: number, | ||
: recursiveReduce( | ||
reducer(acc, car(current), index, collection), | ||
reducer, | ||
callback(acc, car(current), index, collection), | ||
callback, | ||
cdr(current), | ||
@@ -60,11 +60,11 @@ step, | ||
export function reduce<T, R>( | ||
reducer: ReduceFn<T, R>, | ||
callback: ReduceCallback<T, R>, | ||
initial: R, | ||
list: LinkedList<T> | ||
): R { | ||
return recursiveReduce(initial, reducer, list, 1, 0, list) | ||
return recursiveReduce(initial, callback, list, 1, 0, list) | ||
} | ||
export function reduceRight<T, R>( | ||
reducer: ReduceFn<T, R>, | ||
callback: ReduceCallback<T, R>, | ||
initial: R, | ||
@@ -74,7 +74,7 @@ list: LinkedList<T> | ||
const lastIndex = length(list) - 1 | ||
return recursiveReduce(initial, reducer, reverse(list), -1, lastIndex, list) | ||
return recursiveReduce(initial, callback, reverse(list), -1, lastIndex, list) | ||
} | ||
export function map<T, R>( | ||
mapper: MapFunction<T, R>, | ||
callback: MapCallback<T, R>, | ||
list: LinkedList<T> | ||
@@ -85,3 +85,3 @@ ): LinkedList<R> { | ||
(acc, value, index, collection) => | ||
prepend(mapper(value, index, collection), acc), | ||
prepend(callback(value, index, collection), acc), | ||
emptyList(), | ||
@@ -93,2 +93,16 @@ list | ||
export function flatMap<T, R>( | ||
callback: MapCallback<T, LinkedList<R>>, | ||
list: LinkedList<T> | ||
): LinkedList<R> { | ||
return reverse( | ||
reduce( | ||
(acc, value, index, collection) => | ||
concat(reverse(callback(value, index, collection)), acc), | ||
emptyList(), | ||
list | ||
) | ||
) | ||
} | ||
export function filter<T>( | ||
@@ -95,0 +109,0 @@ predicate: PredicateFunction<T>, |
@@ -6,2 +6,3 @@ export { | ||
filter, | ||
flatMap, | ||
head, | ||
@@ -8,0 +9,0 @@ isEmpty, |
@@ -236,13 +236,13 @@ import * as fc from 'fast-check' | ||
test('calls the mapper function for every item in the list', () => { | ||
test('calls the callback function for every item in the list', () => { | ||
fc.assert( | ||
fc.property(arbitraryArray, (items) => { | ||
const list = L.listOf(...items) | ||
const mapper = jest.fn() | ||
const callback = jest.fn() | ||
L.map(mapper, list) | ||
L.map(callback, list) | ||
expect(mapper).toHaveBeenCalledTimes(items.length) | ||
expect(callback).toHaveBeenCalledTimes(items.length) | ||
items.forEach((item, index) => | ||
expect(mapper).toHaveBeenCalledWith(item, index, list) | ||
expect(callback).toHaveBeenCalledWith(item, index, list) | ||
) | ||
@@ -254,7 +254,41 @@ }) | ||
test('creates a new list with the items of the list transformed', () => { | ||
const mapper = (i: number) => i + 1 | ||
expect(L.map(mapper, L.listOf(1, 2, 3))).toEqual(L.listOf(2, 3, 4)) | ||
const callback = (i: number) => i + 1 | ||
expect(L.map(callback, L.listOf(1, 2, 3))).toEqual(L.listOf(2, 3, 4)) | ||
}) | ||
}) | ||
describe('flatMap()', () => { | ||
test('returns an empty list unchanged', () => { | ||
const list = L.listOf() | ||
expect(L.flatMap((i) => L.listOf(i), list)).toEqual(list) | ||
}) | ||
test('calls the callback function for every item in the list', () => { | ||
fc.assert( | ||
fc.property(arbitraryArray, (items) => { | ||
const list = L.listOf(...items) | ||
const callback = jest.fn() | ||
L.flatMap(callback, list) | ||
expect(callback).toHaveBeenCalledTimes(items.length) | ||
items.forEach((item, index) => | ||
expect(callback).toHaveBeenCalledWith(item, index, list) | ||
) | ||
}) | ||
) | ||
}) | ||
test('linked list results are flattened', () => { | ||
const list = L.listOf(1, 2, 3) | ||
expect(L.flatMap((i) => L.listOf(i), list)).toEqual(list) | ||
}) | ||
test('linked list results are flattened in the right order', () => { | ||
const list = L.listOf(1, 2, 3) | ||
const expected = L.listOf(1.1, 1.2, 2.1, 2.2, 3.1, 3.2) | ||
expect(L.flatMap((i) => L.listOf(i + 0.1, i + 0.2), list)).toEqual(expected) | ||
}) | ||
}) | ||
describe('reduce()', () => { | ||
@@ -266,12 +300,12 @@ test('returns the initial value for an empty list', () => { | ||
test('calls the reducer function for every item in the list', () => { | ||
test('calls the callback function for every item in the list', () => { | ||
const list = L.listOf(1, 2, 3) | ||
const reducer = jest.fn((acc, i) => acc + i) | ||
const callback = jest.fn((acc, i) => acc + i) | ||
L.reduce(reducer, 0, list) | ||
L.reduce(callback, 0, list) | ||
expect(reducer).toHaveBeenCalledTimes(3) | ||
expect(reducer).toHaveBeenCalledWith(0, 1, 0, list) | ||
expect(reducer).toHaveBeenCalledWith(1, 2, 1, list) | ||
expect(reducer).toHaveBeenCalledWith(3, 3, 2, list) | ||
expect(callback).toHaveBeenCalledTimes(3) | ||
expect(callback).toHaveBeenCalledWith(0, 1, 0, list) | ||
expect(callback).toHaveBeenCalledWith(1, 2, 1, list) | ||
expect(callback).toHaveBeenCalledWith(3, 3, 2, list) | ||
}) | ||
@@ -292,12 +326,12 @@ | ||
test('calls the reducer function for every item in the list', () => { | ||
test('calls the callback function for every item in the list', () => { | ||
const list = L.listOf(1, 2, 3) | ||
const reducer = jest.fn((acc, i) => acc + i) | ||
const callback = jest.fn((acc, i) => acc + i) | ||
L.reduceRight(reducer, 0, list) | ||
L.reduceRight(callback, 0, list) | ||
expect(reducer).toHaveBeenCalledTimes(3) | ||
expect(reducer).toHaveBeenCalledWith(0, 3, 2, list) | ||
expect(reducer).toHaveBeenCalledWith(3, 2, 1, list) | ||
expect(reducer).toHaveBeenCalledWith(5, 1, 0, list) | ||
expect(callback).toHaveBeenCalledTimes(3) | ||
expect(callback).toHaveBeenCalledWith(0, 3, 2, list) | ||
expect(callback).toHaveBeenCalledWith(3, 2, 1, list) | ||
expect(callback).toHaveBeenCalledWith(5, 1, 0, list) | ||
}) | ||
@@ -304,0 +338,0 @@ |
72154
1653
195