Skip to content

Commit ef9af6e

Browse files
🚧 progress: Import existing sources, tests, and code samples.
1 parent 3358b85 commit ef9af6e

File tree

8 files changed

+10189
-12
lines changed

8 files changed

+10189
-12
lines changed

README.md

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,18 @@
44
Set n-multicombinations for JavaScript.
55
See [docs](https://computational-combinatorics.github.io/n-multicombinations/index.html).
66

7-
> :building_construction: Caveat emptor! This is work in progress. Code may be
8-
> working. Documentation may be present. Coherence may be. Maybe.
9-
107
> :warning: Depending on your environment, the code may require
118
> `regeneratorRuntime` to be defined, for instance by importing
129
> [regenerator-runtime/runtime](https://www.npmjs.com/package/regenerator-runtime).
1310
11+
```
12+
import {multicombinations} from '@combinatorics/n-multicombinations';
13+
multicombinations("ABC", 1); // A B C
14+
15+
import {range} from '@iterable-iterator/range';
16+
multicombinations(range(3), 2); // 00 01 02 11 12 22
17+
```
18+
1419
[![License](https://img.shields.io/github/license/computational-combinatorics/n-multicombinations.svg)](https://raw.githubusercontent.com/computational-combinatorics/n-multicombinations/main/LICENSE)
1520
[![Version](https://img.shields.io/npm/v/@combinatorics/n-multicombinations.svg)](https://www.npmjs.org/package/@combinatorics/n-multicombinations)
1621
[![Tests](https://img.shields.io/github/workflow/status/computational-combinatorics/n-multicombinations/ci:test?event=push&label=tests)](https://github.com/computational-combinatorics/n-multicombinations/actions/workflows/ci:test.yml?query=branch:main)

doc/scripts/header.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,8 @@ domReady(() => {
1717
header.insertBefore(projectname, header.firstChild);
1818

1919
const testlink = document.querySelector('header > a[data-ice="testLink"]');
20-
testlink.href = 'https://app.codecov.io/gh/computational-combinatorics/n-multicombinations';
20+
testlink.href =
21+
'https://app.codecov.io/gh/computational-combinatorics/n-multicombinations';
2122
testlink.target = '_BLANK';
2223

2324
const searchBox = document.querySelector('.search-box');

package.json

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,12 +63,17 @@
6363
"release": "np --message ':hatching_chick: release: Bumping to v%s.'",
6464
"test": "ava"
6565
},
66-
"dependencies": {},
66+
"dependencies": {
67+
"@iterable-iterator/list": "^0.0.2",
68+
"@iterable-iterator/map": "^0.1.0",
69+
"@iterable-iterator/repeat": "^0.0.1"
70+
},
6771
"devDependencies": {
6872
"@babel/core": "7.14.0",
6973
"@babel/preset-env": "7.14.0",
7074
"@babel/register": "7.13.16",
7175
"@commitlint/cli": "12.1.1",
76+
"@iterable-iterator/range": "^1.0.0",
7277
"@js-library/commitlint-config": "0.0.4",
7378
"ava": "3.15.0",
7479
"babel-plugin-transform-remove-console": "6.9.4",

src/index.js

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1 @@
1-
const answer = 42;
2-
export default answer;
1+
export {default as multicombinations} from './multicombinations.js';

src/multicombinations.js

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
import {list} from '@iterable-iterator/list';
2+
import {pick} from '@iterable-iterator/map';
3+
import {nrepeat} from '@iterable-iterator/repeat';
4+
5+
/**
6+
* Yields all combinations, with repetitions, of each possible choice of
7+
* <code>r</code> elements of the input iterable.
8+
*
9+
* @example
10+
* // A B C
11+
* multicombinations('ABC', 1)
12+
*
13+
* @example
14+
* // 00 01 02 11 12 22
15+
* multicombinations(range(3), 2)
16+
*
17+
* @param {Iterable} iterable - The input iterable.
18+
* @param {number} r - The size of the combinations to generate.
19+
* @returns {IterableIterator}
20+
*/
21+
export default function* multicombinations(iterable, r) {
22+
const pool = list(iterable);
23+
const length = pool.length;
24+
25+
if (length === 0 && r > 0) {
26+
return;
27+
}
28+
29+
const indices = list(nrepeat(0, r));
30+
31+
yield list(pick(pool, indices));
32+
33+
while (true) {
34+
let i = r - 1;
35+
36+
// eslint-disable-next-line no-constant-condition
37+
while (true) {
38+
if (i < 0) {
39+
return;
40+
}
41+
42+
if (indices[i] !== length - 1) {
43+
const pivot = ++indices[i];
44+
45+
for (++i; i < r; ++i) {
46+
indices[i] = pivot;
47+
}
48+
49+
break;
50+
}
51+
52+
--i;
53+
}
54+
55+
yield list(pick(pool, indices));
56+
}
57+
}

test/src/api.js

Lines changed: 0 additions & 5 deletions
This file was deleted.

test/src/multicombinations.js

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
import test from 'ava';
2+
3+
import {list} from '@iterable-iterator/list';
4+
import {range} from '@iterable-iterator/range';
5+
import {multicombinations} from '../../src/index.js';
6+
7+
const repr = (x) => (Array.isArray(x) ? JSON.stringify(x) : x);
8+
9+
const macro = (t, iterable, r, expected) => {
10+
t.deepEqual(list(multicombinations(iterable, r)), expected);
11+
};
12+
13+
macro.title = (title, iterable, r, expected) =>
14+
title ?? `multicombinations(${repr(iterable)}, ${r}) is ${repr(expected)}`;
15+
16+
test(macro, 'ABC', 2, [
17+
['A', 'A'],
18+
['A', 'B'],
19+
['A', 'C'],
20+
['B', 'B'],
21+
['B', 'C'],
22+
['C', 'C'],
23+
]);
24+
test(macro, range(0, 3, 1), 2, [
25+
[0, 0],
26+
[0, 1],
27+
[0, 2],
28+
[1, 1],
29+
[1, 2],
30+
[2, 2],
31+
]);
32+
test(macro, range(0, 0, 1), 2, []);
33+
test(macro, range(0, 4, 1), 0, [[]]);
34+
test(macro, range(0, 0, 1), 0, [[]]);

0 commit comments

Comments
 (0)