Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
42 commits
Select commit Hold shift + click to select a range
e3d7111
ready to publish
chalu Feb 18, 2024
51add33
add CD workflow
chalu Feb 18, 2024
16d3398
lint only changed TS or JS files
chalu Feb 18, 2024
d0de98d
fix CD job name
chalu Feb 18, 2024
83348c4
run CI only on PR to dev or main
chalu Feb 18, 2024
d8979e9
dry run package publishing
chalu Feb 18, 2024
c29a94d
merge branch 'main' into go-publish
chalu Feb 18, 2024
829d598
Merge branch 'dev' into go-publish
chalu Feb 18, 2024
2b39e3e
dry run publish on dev branch
chalu Feb 18, 2024
55a6922
sync local and remote branches
chalu Feb 18, 2024
0cfbc03
get production ready
chalu Feb 18, 2024
bbf5f0b
make a default tsconfig from the ESM config
chalu Feb 18, 2024
41ba737
dry run release from GHA
chalu Feb 18, 2024
01996d9
Merge branch 'dev' into go-publish
chalu Feb 18, 2024
d706086
prune GHA runs
chalu Feb 18, 2024
a3ba02f
update with merge conflict resolution commit
chalu Feb 18, 2024
0d3d8b1
attempt release from GHA
chalu Feb 18, 2024
670b7c1
attempt release from GHA
chalu Feb 18, 2024
d837f27
Merge branch 'dev' into go-publish
chalu Feb 18, 2024
b528f0c
fix package json file
chalu Feb 18, 2024
f0a3f5f
fix version
chalu Feb 18, 2024
8fd0e34
Merge branch 'dev' into go-publish
chalu Feb 18, 2024
2a29104
remove merged condition
chalu Feb 18, 2024
db42545
fix version
chalu Feb 18, 2024
f176ab0
fix version
chalu Feb 18, 2024
1d5adb1
use latest tag
chalu Feb 18, 2024
387b3e2
fix release workflow
chalu Feb 18, 2024
dd323c0
prepare first public release
chalu Feb 18, 2024
33b9183
set first public release
chalu Feb 18, 2024
120dd89
Merge branch 'dev' into go-publish
chalu Feb 18, 2024
dba7f3e
remove files filter from lint script
chalu Feb 28, 2024
95e196e
simplify types used
chalu Feb 28, 2024
6f6a4ad
refine lint script for pre-commit hook
chalu Mar 5, 2024
b41eb14
fix cjs and esm modules
chalu Mar 5, 2024
ba0f900
add updated build
chalu Mar 5, 2024
994f562
fix lint errors in esm example code
chalu Mar 5, 2024
854d604
add more JS examples
chalu Mar 6, 2024
b0f35e3
document what is exported
chalu Mar 6, 2024
d076ec3
document what is exported
chalu Mar 6, 2024
1e8584a
update build
chalu Mar 6, 2024
6f347fb
bump patch version
chalu Mar 6, 2024
ff1ef63
Merge branch 'dev' into patch-release
chalu Mar 6, 2024
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
2 changes: 1 addition & 1 deletion .husky/pre-commit
Original file line number Diff line number Diff line change
@@ -1 +1 @@
pnpm lint
pnpm lint:MA
1 change: 1 addition & 0 deletions .xo-config.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
{
"env": ["jest", "node"],
"rules": {
"no-await-in-loop": "off",
"import/extensions": "off",
"unicorn/prefer-module": "off",
"unicorn/no-array-for-each": "off",
Expand Down
43 changes: 23 additions & 20 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,57 +1,60 @@
# n-tuple-array

Get a specified amount of items when iterating over a JavaScript array, instead of the single item that arrays provide per iteration, by default.
Get a **`configurable`** amount of items when iterating over a JavaScript array, instead of a single item that arrays provide per iteration, by default.


## Motivation

Imagine that you received a collection of coordinates (latitude and longitude), but they were sent
as a flat array of values to speed up the data transfers.
Imagine that you received a large collection of coordinates (latitude and longitude), but they were sent
as a flat array of values to speed up the data transfer.

`n-tuple-array` can help you get out the coordinates in pairs (their logical representation), such that you'd go **from**
`n-tuple-array` can help you get out the coordinates in pairs (i.e their logical representation), such that you'd go

**from**
```json
// flatCoords
// flat coordinates
["5.7225", "-9.6273", "2.68452", "-30.9501", ...]
```

**to**
```javascript
// generate pairs by default
const coordIterable = tuplesFromArray({ list: flatCoords });
// the iterable will generate pairs by default
const coordsIterable = tuplesFromArray({ list: flatCoords });

// using for..of, get pairs as ["5.7225", "-9.6273"] ...
for (const pair of coordIterable) {
for (const pair of coordsIterable) {
console.log(pair);
}

// OR manipulate pairs with regular array functions
const coordPairs = Array.from(coordIterable);
console.log(Array.isArray(coordPairs)); // true
// prints ["5.7225", "-9.6273"] ...
coordPairs
// OR manipulate pairs with regular array
// functions like map, filter, forEach ...
const coordsInPairs = Array.from(coordsIterable);
console.log(Array.isArray(coordsInPairs)); // true
coordsInPairs
.map(pair => {
// pair is ["5.7225", "-9.6273"] ...
return myTransform(pair);
})
.forEach((pair) => {
// pair is ["5.7225", "-9.6273"] ...
placeOnMap(pair);
});
```

### Some Real World Examples

#### Wole Joko
#### 1. Wole Joko

I first tried my hands on this concept when [building wole-joko](https://github.com/chalu/wole-joko/blob/dev/src/js/utils.js#L57-L92), a _live coding task_ I was asked to do in an engineering manager interview :man_shrugging. It was a simulation of people entering an event hall to get seated, but only two could get in at a time. I later took some time to [give the project more life](https://wole-joko.netlify.app/)
I first tried my hands on this concept when [fleshing out wole-joko](https://github.com/chalu/wole-joko/blob/dev/src/js/utils.js#L57-L92), which strated as a _live coding task_ I was asked to do in an engineering manager interview :man_shrugging
It was a simulation of people entering an event hall to get seated, but **only two** could get in at a time - https://wole-joko.netlify.app/

#### Execute max of X tasks in parallel
#### 2. Execute max of `N` async tasks

JS challenge by [@thdxr on X.com](https://twitter.com/thdxr) <br>
![](./assets/the-dax-js-challenge.png "JS challenge by @thdxr")
<br> <br>

> The below was adapted for more concise terminal output

`n-tuple-array` solution. View [code here](https://github.com/chalu/n-tuple-array/blob/main/src/demo/demo-classic.ts#L6-L40) <br>
`n-tuple-array` solution. View [code here](https://github.com/chalu/n-tuple-array/blob/main/src/examples/classic.ts#L6-L40) <br>
![](./assets/demo-classic.png "n-tuple-array solution")
<br> <br>

Expand Down Expand Up @@ -92,5 +95,5 @@ for (const quintet of quintetIterator) {
}
```

See more examples in [src/demo](./src/demo/)
See more examples in [src/examples](./src/examples/)

37 changes: 34 additions & 3 deletions dist/cjs/index.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions dist/cjs/index.js.map

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions dist/cjs/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"type": "commonjs"
}
46 changes: 43 additions & 3 deletions dist/cjs/types/index.d.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,53 @@
type Item<T> = T | undefined;
type Value<T> = Array<Item<T>>;
export type Matcher<T> = (item: T | unknown) => boolean;
export type TupleConfig<T> = {
/**
* The input array to use
*/
list: T[];
/**
* The max number of items to return from the input array, per iteration
* @defaultValue 2
*/
maxItems?: number;
/**
* When provided, a function used to determine which items in the input array
* are eligible to be included, per iteration
*/
match?: Matcher<T>;
};
/**
* An exception than can be thrown if there is no input array, `maxItems` is <= 0 or is not
* a number, or `match` is not a function
*/
export declare class InvalidInvocationParameterError extends Error {
}
export declare const tuplesFromArray: <T>(config: TupleConfig<T>) => Iterable<Value<T>>;
/**
* Returns an iterable iterator that ouputs a configured
* list of items when iterating over a given array
*
* @typeParam T - Type of items the input list contains
*
* @param config - An object to indicate the input array `config.list`, and set the
* max size of items per interation `config.maxItems`. You can also optionally specify `config.match`
* as a function that should return true to filter in items from the input array
* (or false to filter them out) when deciding what items is to be included per iteration
*
* @function
* @throws InvalidInvocationParameterError
* This exception is thrown if there is no input array, `maxItems` is <= 0 or is not
* a number, or `match` is not a function
*
* @returns an IterableIterator
*
* @example
* Here is an example that will get max of 3 items from
* each iteration on the returned iterable
* ```javascript
* const iterable = tuplesFromArray({
* list:[], maxSize: 3, match: (itm) => !!itm
* });
* ```
*/
export declare const tuplesFromArray: <T>(config: TupleConfig<T>) => IterableIterator<(T | undefined)[]>;
export default tuplesFromArray;
//# sourceMappingURL=index.d.ts.map
2 changes: 1 addition & 1 deletion dist/cjs/types/index.d.ts.map

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions dist/esm/index.js.map

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

48 changes: 37 additions & 11 deletions dist/esm/index.mjs
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.tuplesFromArray = exports.InvalidInvocationParameterError = void 0;
class InvalidInvocationParameterError extends Error {
/**
* An exception than can be thrown if there is no input array, `maxItems` is <= 0 or is not
* a number, or `match` is not a function
*/
export class InvalidInvocationParameterError extends Error {
}
exports.InvalidInvocationParameterError = InvalidInvocationParameterError;
const validateParametersOrThrow = (list, maxItems, match) => {
if (!list || !Array.isArray(list)) {
throw new InvalidInvocationParameterError('expected list to be an array');
Expand All @@ -18,7 +18,34 @@ const validateParametersOrThrow = (list, maxItems, match) => {
throw new InvalidInvocationParameterError(message);
}
};
const tuplesFromArray = (config) => {
/**
* Returns an iterable iterator that ouputs a configured
* list of items when iterating over a given array
*
* @typeParam T - Type of items the input list contains
*
* @param config - An object to indicate the input array `config.list`, and set the
* max size of items per interation `config.maxItems`. You can also optionally specify `config.match`
* as a function that should return true to filter in items from the input array
* (or false to filter them out) when deciding what items is to be included per iteration
*
* @function
* @throws InvalidInvocationParameterError
* This exception is thrown if there is no input array, `maxItems` is <= 0 or is not
* a number, or `match` is not a function
*
* @returns an IterableIterator
*
* @example
* Here is an example that will get max of 3 items from
* each iteration on the returned iterable
* ```javascript
* const iterable = tuplesFromArray({
* list:[], maxSize: 3, match: (itm) => !!itm
* });
* ```
*/
export const tuplesFromArray = (config) => {
const { list, match, maxItems = 2 } = config;
validateParametersOrThrow(list, maxItems, match);
let cursor = 0;
Expand Down Expand Up @@ -50,13 +77,12 @@ const tuplesFromArray = (config) => {
return { value: items, done: items.length === 0 };
};
const iterable = {
next: proceedNext,
[Symbol.iterator]() {
return {
next: proceedNext,
};
return this;
},
};
return iterable;
};
exports.tuplesFromArray = tuplesFromArray;
exports.default = exports.tuplesFromArray;
export default tuplesFromArray;
//# sourceMappingURL=index.js.map
3 changes: 3 additions & 0 deletions dist/esm/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"type": "module"
}
46 changes: 43 additions & 3 deletions dist/esm/types/index.d.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,53 @@
type Item<T> = T | undefined;
type Value<T> = Array<Item<T>>;
export type Matcher<T> = (item: T | unknown) => boolean;
export type TupleConfig<T> = {
/**
* The input array to use
*/
list: T[];
/**
* The max number of items to return from the input array, per iteration
* @defaultValue 2
*/
maxItems?: number;
/**
* When provided, a function used to determine which items in the input array
* are eligible to be included, per iteration
*/
match?: Matcher<T>;
};
/**
* An exception than can be thrown if there is no input array, `maxItems` is <= 0 or is not
* a number, or `match` is not a function
*/
export declare class InvalidInvocationParameterError extends Error {
}
export declare const tuplesFromArray: <T>(config: TupleConfig<T>) => Iterable<Value<T>>;
/**
* Returns an iterable iterator that ouputs a configured
* list of items when iterating over a given array
*
* @typeParam T - Type of items the input list contains
*
* @param config - An object to indicate the input array `config.list`, and set the
* max size of items per interation `config.maxItems`. You can also optionally specify `config.match`
* as a function that should return true to filter in items from the input array
* (or false to filter them out) when deciding what items is to be included per iteration
*
* @function
* @throws InvalidInvocationParameterError
* This exception is thrown if there is no input array, `maxItems` is <= 0 or is not
* a number, or `match` is not a function
*
* @returns an IterableIterator
*
* @example
* Here is an example that will get max of 3 items from
* each iteration on the returned iterable
* ```javascript
* const iterable = tuplesFromArray({
* list:[], maxSize: 3, match: (itm) => !!itm
* });
* ```
*/
export declare const tuplesFromArray: <T>(config: TupleConfig<T>) => IterableIterator<(T | undefined)[]>;
export default tuplesFromArray;
//# sourceMappingURL=index.d.ts.map
2 changes: 1 addition & 1 deletion dist/esm/types/index.d.ts.map

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

11 changes: 11 additions & 0 deletions fix-pkgs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
cat >dist/cjs/package.json <<!EOF
{
"type": "commonjs"
}
!EOF

cat >dist/esm/package.json <<!EOF
{
"type": "module"
}
!EOF
Loading