-
Notifications
You must be signed in to change notification settings - Fork 10
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #88 from poteat/poteat/object-countby
Add countBy and other List utilities, + some runtime functions and tests.
- Loading branch information
Showing
28 changed files
with
535 additions
and
40 deletions.
There are no files selected for viewing
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
File renamed without changes.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -23,3 +23,18 @@ import { Kind } from '..' | |
export interface Identity extends Kind.Kind { | ||
f(x: this[Kind._]): typeof x | ||
} | ||
|
||
/** | ||
Check warning on line 27 in src/function/identity.ts GitHub Actions / build-stress
|
||
* Given a value, return the value. | ||
* | ||
* @param {unknown} x - The value to return. | ||
Check warning on line 30 in src/function/identity.ts GitHub Actions / build-stress
|
||
* | ||
* @example | ||
* ```ts | ||
* import { Function } from "hkt-toolbelt"; | ||
* | ||
* const result = Function.identity('foo') | ||
* // ^? foo | ||
* ``` | ||
*/ | ||
export const identity = ((x: unknown) => x) as Kind._$reify<Identity> |
File renamed without changes.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,4 @@ | ||
import { Function, Kind, List, Type } from '..' | ||
import { $, Function, Kind, List, Type } from '..' | ||
|
||
/** | ||
* `_$pipe` is a type-level function that allows users to compose | ||
|
@@ -29,12 +29,16 @@ import { Function, Kind, List, Type } from '..' | |
* and `Kind.OutputOf` type-level functions to inspect the input and output | ||
* types of the type-level functions that you are piping together. | ||
*/ | ||
export type _$pipe<FX extends Kind.Kind[], X> = Kind._$compose< | ||
List._$reverse<FX>, | ||
X | ||
> | ||
export type _$pipe<T extends Kind.Kind[], X> = T extends [ | ||
infer Head extends Kind.Kind, | ||
...infer Tail extends Kind.Kind[] | ||
] | ||
? [X] extends [never] | ||
? never | ||
: _$pipe<Tail, $<Head, Type._$cast<X, Kind._$inputOf<Head>>>> | ||
: X | ||
|
||
interface Pipe_T<FX extends Kind.Kind[]> extends Kind.Kind { | ||
export interface Pipe_T<FX extends Kind.Kind[]> extends Kind.Kind { | ||
f( | ||
x: Type._$cast< | ||
this[Kind._], | ||
|
@@ -84,6 +88,9 @@ export interface Pipe extends Kind.Kind { | |
* Given a list of functions, pipe the functions together, applying them in | ||
* order from left to right. | ||
* | ||
* @param {Kind.Kind[]} fx - A list of functions to pipe together. | ||
Check warning on line 91 in src/kind/pipe.ts GitHub Actions / build-stress
|
||
* @param {InputOf<FX[0]>} x - The input to pipe through the functions. | ||
Check warning on line 92 in src/kind/pipe.ts GitHub Actions / build-stress
Check warning on line 92 in src/kind/pipe.ts GitHub Actions / build-stress
|
||
* | ||
* @example | ||
* ```ts | ||
* import { Kind, NaturalNumber } from "hkt-toolbelt"; | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
import { $, Function, List, Test } from '..' | ||
|
||
type CountBy_Spec = [ | ||
/** | ||
* Can count by a predicate. | ||
*/ | ||
Test.Expect< | ||
$<$<List.CountBy, Function.Identity>, [1, 1, 1, 2, 3]>, | ||
{ | ||
1: 3 | ||
2: 1 | ||
3: 1 | ||
} | ||
>, | ||
|
||
/** | ||
* Can count by a predicate with a constant. | ||
*/ | ||
Test.Expect< | ||
$<$<List.CountBy, $<Function.Constant, 'foo'>>, ['foo', 'foo', 'bar']>, | ||
{ | ||
foo: 3 | ||
} | ||
>, | ||
|
||
/** | ||
* Can count by a 'length' predicate over lists. | ||
*/ | ||
Test.Expect< | ||
$<$<List.CountBy, List.Length>, [[1, 2, 3], [1, 2, 3, 4], [1, 2, 3]]>, | ||
{ | ||
3: 2 | ||
4: 1 | ||
} | ||
> | ||
] | ||
|
||
it('should return the count of each unique element', () => { | ||
expect(List.countBy(Function.identity)(['foo', 'foo', 'bar'])).toEqual({ | ||
foo: 2, | ||
bar: 1 | ||
}) | ||
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,91 @@ | ||
import { $, Kind, NaturalNumber, Object, Type, Function } from '..' | ||
|
||
type _$countBy2< | ||
F extends Kind.Kind, | ||
T extends unknown[], | ||
O extends Record<string | number | symbol, number> = {} | ||
> = T extends [infer Head extends Kind._$inputOf<F>, ...infer Tail] | ||
? _$countBy2< | ||
F, | ||
Tail, | ||
$<F, Head> extends infer NewKey extends PropertyKey | ||
? Object._$assign< | ||
NewKey, | ||
NewKey extends keyof O ? NaturalNumber._$increment<O[NewKey]> : 1, | ||
O | ||
> | ||
: never | ||
> | ||
: O | ||
|
||
/** | ||
* `_$countBy` is a type-level function that takes in a kind `K` that returns a | ||
* string, number, or symbol, and a list `T`, and returns a map of the counts | ||
* of the elements in `T` mapped by the result of applying `K` to each element. | ||
* | ||
* @template {Kind} F - The kind that returns a string, number, or symbol. | ||
* @template {unknown[]} T - The list to count the elements of. | ||
* | ||
* @example | ||
* ```ts | ||
* type T0 = _$countBy<Function.Identity, ['foo', 'foo', 'bar']> // { foo: 2, bar: 1 } | ||
* type T1 = _$countBy<String.Length, ['foo', 'foo', 'quxes']> // { 3: 2, 5: 1 } | ||
* ``` | ||
*/ | ||
export type _$countBy< | ||
F extends Kind.Kind, | ||
T extends unknown[], | ||
O extends Record<string | number | symbol, number> = {} | ||
> = Type._$display<_$countBy2<F, T, O>> | ||
|
||
export interface CountBy_T<F extends Kind.Kind> extends Kind.Kind { | ||
f(x: Type._$cast<this[Kind._], unknown[]>): _$countBy<F, typeof x> | ||
} | ||
|
||
/** | ||
* `CountBy` is a type-level function that takes in a kind `K` that returns a | ||
* string, number, or symbol, and a list `T`, and returns a map of the counts | ||
* of the elements in `T` mapped by the result of applying `K` to each element. | ||
* | ||
* @template {Kind} F - The kind that returns a string, number, or symbol. | ||
* @template {unknown[]} T - The list to count the elements of. | ||
* | ||
* @example | ||
* ```ts | ||
* type T0 = $<$<$<List.CountBy, Function.Identity>, ['foo', 'foo', 'bar']> // { foo: 2, bar: 1 } | ||
* type T1 = $<$<$<List.CountBy, String.Length>, ['foo', 'foo', 'quxes']> // { 3: 2, 5: 1 } | ||
* ``` | ||
*/ | ||
export interface CountBy extends Kind.Kind { | ||
f(x: Type._$cast<this[Kind._], Kind.Kind>): CountBy_T<typeof x> | ||
} | ||
|
||
/** | ||
* Given a list, return a new list containing the count of each unique element. | ||
* | ||
* @param {Kind.Kind} f - The function to apply to each element to get the key. | ||
* @param {unknown[]} values - The list to count the elements of. | ||
* | ||
* @example | ||
* ```ts | ||
* import { List, Function } from "hkt-toolbelt"; | ||
* | ||
* const result = List.countBy(Function.identity)(['foo', 'foo', 'bar']) | ||
* // ^? { foo: 2, bar: 1 } | ||
* ``` | ||
*/ | ||
export const countBy = ((f: Function.Function) => (values: unknown[]) => { | ||
const result = {} as Record<string | number | symbol, number> | ||
|
||
for (const element of values) { | ||
const key = f(element as never) as string | number | symbol | ||
|
||
if (key in result) { | ||
result[key]++ | ||
} else { | ||
result[key] = 1 | ||
} | ||
} | ||
|
||
return result | ||
}) as Kind._$reify<CountBy> |
File renamed without changes.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
File renamed without changes.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
import { $, Test, List, Function, String } from '..' | ||
|
||
type MaxBy_Spec = [ | ||
/** | ||
* Can find the maximum element of a list of numbers. | ||
*/ | ||
Test.Expect<$<$<List.MaxBy, Function.Identity>, [1, 2, 3]>, 3>, | ||
|
||
/** | ||
* Can find the maximum element of a list of strings, based on length. | ||
*/ | ||
Test.Expect<$<$<List.MaxBy, String.Length>, ['foo', 'bars', 'qux']>, 'bars'> | ||
] | ||
|
||
it('should return the element in the list that has the highest score', () => { | ||
expect(List.maxBy(Function.identity)([1, 2, 3])).toBe(3) | ||
}) |
Oops, something went wrong.