Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement all and any, and make documentation example runnable #13

Merged
merged 1 commit into from
Feb 1, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 34 additions & 0 deletions mod.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -99,3 +99,37 @@ Deno.test("partialCmpBy", () => {
assert(some(res) && res > 0);
}
});

Deno.test("all", () => {
{
const iter = new Iter([1, 2, 3, 4]);
assert(iter.all((n) => n > 0));
assert(iter.next().done, "iterator shall be fully consumed");
}
{
const iter = new Iter([1, 2, 3, 4]);
assert(!iter.all((n) => n < 3));
const next = iter.next();
assert(
!next.done && next.value === 4,
"iterator shall not be fully consumed",
);
}
});

Deno.test("any", () => {
{
const iter = new Iter([1, 2, 3, 4]);
assert(iter.any((n) => n > 2));
const next = iter.next();
assert(
!next.done && next.value === 4,
"iterator shall not be fully consumed",
);
}
{
const iter = new Iter([1, 2, 3, 4]);
assert(!iter.any((n) => n < 1));
assert(iter.next().done, "iterator shall be fully consumed");
}
});
84 changes: 69 additions & 15 deletions mod.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ export default class Iter<T> implements IterableIterator<T> {
/**
* Wraps any object that is an iterable or an iterator in
* an Iter object
*
* @param iter The object to wrap
*/
constructor(iter: IntoIter<T>) {
Expand All @@ -84,10 +85,10 @@ export default class Iter<T> implements IterableIterator<T> {
*
* @example
* const it = new Iter([1, 2, 3]);
* let { value, done } = it.next(); // value === 1, done == false
* ({ value, done } = it.next()); // value === 2, done == false
* ({ value, done } = it.next()); // value === 3, done == false
* ({ value, done } = it.next()); // typeof value === "undefined", done === true
* let { value, done } = it.next(); assert(value === 1 && !done);
* ({ value, done } = it.next()); assert(value === 2 && !done);
* ({ value, done } = it.next()); assert(value === 3 && !done);
* ({ value, done } = it.next()); assert(typeof value === "undefined" && done);
*/
next(): IteratorResult<T> {
return this.iter.next();
Expand Down Expand Up @@ -122,7 +123,7 @@ export default class Iter<T> implements IterableIterator<T> {
* @example
* const set = new Set(["doorknob", "cappucino", "cappucino", "pianissimo", "baz", "abdicate"]);
* const word = new Iter(set).fold('', (acc, w) => acc + w.slice(-1));
* console.log(word); // booze
* assertStrictEquals(word, "booze");
*
* @param init The accumulator's initial value.
* @param f Function that takes as arguments the
Expand Down Expand Up @@ -274,7 +275,7 @@ export default class Iter<T> implements IterableIterator<T> {
*
* const arr = ["lol", "NaN", "2", "5"];
* const firstNumber = new Iter(arr).findMap(coolParseInt);
* // firstNumber === 2
* assertStrictEquals(firstNumber, 2);
*
* @param f The function to apply
* @returns The first non-null value after the function was applied, if any
Expand All @@ -296,8 +297,7 @@ export default class Iter<T> implements IterableIterator<T> {
* @example
* const numbers = [1, 2, 3, 4, 5];
* const coolNumbers = [...new Iter(numbers).filter((n) => n > 2)];
* console.log(coolNumbers);
* // [ 3, 4, 5, ]
* assertEquals(coolNumbers, [ 3, 4, 5, ]);
*
* @param p The predicate to be satisfied
*/
Expand Down Expand Up @@ -326,8 +326,7 @@ export default class Iter<T> implements IterableIterator<T> {
* return num;
* }
* const numbers = [...new Iter(["a", "b", "1", "2", "c"]).filterMap(coolParseInt)];
* console.log(numbers);
* // [ 1, 2 ]
* assertEquals(numbers, [1, 2]);
*
* @param f The function to be applied
*/
Expand Down Expand Up @@ -357,8 +356,7 @@ export default class Iter<T> implements IterableIterator<T> {
*
* @example
* const square = [...new Iter([1, 2, 3, 4]).map((n) => n * n)];
* console.log(square)
* // [ 1, 4, 9, 16 ]
* assertEquals(square, [1, 4, 9, 16]);
*
* @example
* const arr = [1, 2, 3, 4];
Expand Down Expand Up @@ -545,6 +543,7 @@ export default class Iter<T> implements IterableIterator<T> {
* return false, which is not a valid result in this situation.
*
* @example
*
* function cmpNumbers(lhs: nummber, rhs: number): Option<number> {
* if (Number.isNaN(lhs) || Number.isNaN(rhs)) {
* return null;
Expand All @@ -553,9 +552,9 @@ export default class Iter<T> implements IterableIterator<T> {
* }
*
* const lhs = [1.0, 2.3, 4.6, 7.8];
* new Iter(lhs).partialCmpBy([1.0, 2.3, 4.6, 7.8], cmpNumbers) // === 0
* new Iter(lhs).partialCmpBy([1.0, 2.2, NaN, 7.8], cmpNumbers) // > 0
* new Iter(lhs).partialCmpBy([1.0, 2.3, NaN, 7.8], cmpNumbers) // === null
* assert(new Iter(lhs).partialCmpBy([1.0, 2.3, 4.6, 7.8], cmpNumbers) === 0);
* assert(new Iter(lhs).partialCmpBy([1.0, 2.2, NaN, 7.8], cmpNumbers) > 0);
* assert(new Iter(lhs).partialCmpBy([1.0, 2.3, NaN, 7.8], cmpNumbers) === null);
*
* @param i The iterable or iterator to compare to.
* @param cmp The comparison function.
Expand Down Expand Up @@ -586,4 +585,59 @@ export default class Iter<T> implements IterableIterator<T> {
}
}
}

/**
* **all** tests if every element of the iterator satisfies
* the given predicate.
*
* This function short-circuits on first occurence of false,
* which means the rest of the elements after the first that
* does not satisfy the predicate are still available for
* iteration.
*
* @example
*
* assert(new Iter([1, 2, 3]).all((n) => n > 0));
*
* @example
*
* const iter = new Iter([1, 2, 3]);
* assert(!iter.all((n) => n !== 2));
* assertStrictEquals(iter.next().value, 3);
*
* @param p The predicate to be satisfied
*/
all(p: (v: T) => boolean): boolean {
return this.tryFold(
undefined,
(_, v) => ({ success: p(v), value: undefined }),
).success;
}

/**
* **any** tests if any element in the iterator satisfies the
* predicate.
*
* This function short-circuits on the first occurrence of true,
* which means the rest of elements after the first element
* that satisfied the predicate are still available for iteration.
*
* @example
*
* assert(new Iter([1, 2, 3]).any((n) => n > 0));
*
* @example
*
* const iter = new Iter([1, 2, 3]);
* assert(iter.any((n) => n !== 2));
* assertStrictEquals(iter.next().value, 2);
*
* @param p The predicate to be satisfied
*/
any(p: (v: T) => boolean): boolean {
return !this.tryFold(
undefined,
(_, v) => ({ success: !p(v), value: undefined }),
).success;
}
}