Skip to content

Commit b80d760

Browse files
committedMay 5, 2021
🚧 progress: Import existing sources, tests, and code samples.
1 parent 21bfc97 commit b80d760

File tree

8 files changed

+10235
-12
lines changed

8 files changed

+10235
-12
lines changed
 

‎README.md

+8-3
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,18 @@
44
Set n-permutations for JavaScript.
55
See [docs](https://computational-combinatorics.github.io/n-permutations/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+
```js
12+
import {permutations} from '@combinatorics/n-permutations';
13+
permutations("ABCD", 2); // AB AC AD BA BC BD CA CB CD DA DB DC
14+
15+
import {range} from '@iterable-iterator/range';
16+
permutations(range(3), 3); // 012 021 102 120 201 210
17+
```
18+
1419
[![License](https://img.shields.io/github/license/computational-combinatorics/n-permutations.svg)](https://raw.githubusercontent.com/computational-combinatorics/n-permutations/main/LICENSE)
1520
[![Version](https://img.shields.io/npm/v/@combinatorics/n-permutations.svg)](https://www.npmjs.org/package/@combinatorics/n-permutations)
1621
[![Tests](https://img.shields.io/github/workflow/status/computational-combinatorics/n-permutations/ci:test?event=push&label=tests)](https://github.com/computational-combinatorics/n-permutations/actions/workflows/ci:test.yml?query=branch:main)

‎doc/scripts/header.js

+2-1
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-permutations';
20+
testlink.href =
21+
'https://app.codecov.io/gh/computational-combinatorics/n-permutations';
2122
testlink.target = '_BLANK';
2223

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

‎package.json

+6-1
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,12 @@
5858
"release": "np --message ':hatching_chick: release: Bumping to v%s.'",
5959
"test": "ava"
6060
},
61-
"dependencies": {},
61+
"dependencies": {
62+
"@iterable-iterator/list": "^0.0.2",
63+
"@iterable-iterator/map": "^0.1.0",
64+
"@iterable-iterator/range": "^1.0.0",
65+
"@iterable-iterator/slice": "^0.0.1"
66+
},
6267
"devDependencies": {
6368
"@babel/core": "7.14.0",
6469
"@babel/preset-env": "7.14.0",

‎src/index.js

+1-2
Original file line numberDiff line numberDiff line change
@@ -1,2 +1 @@
1-
const answer = 42;
2-
export default answer;
1+
export {default as permutations} from './permutations.js';

‎src/permutations.js

+68
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
import assert from 'assert';
2+
import {_take} from '@iterable-iterator/slice';
3+
4+
import {list} from '@iterable-iterator/list';
5+
import {pick} from '@iterable-iterator/map';
6+
import {range} from '@iterable-iterator/range';
7+
8+
/**
9+
* Yields all permutations of each possible choice of <code>r</code> elements
10+
* of the input iterable.
11+
*
12+
* @example
13+
* // AB AC AD BA BC BD CA CB CD DA DB DC
14+
* permutations('ABCD', 2) ;
15+
*
16+
* @example
17+
* // 012 021 102 120 201 210
18+
* permutations(range(3), 3) ;
19+
*
20+
* @param {Iterable} iterable - The input iterable.
21+
* @param {number} r - The size of the permutations to generate.
22+
* @returns {IterableIterator}
23+
*/
24+
export default function* permutations(iterable, r) {
25+
assert(Number.isInteger(r) && r >= 0);
26+
const pool = list(iterable);
27+
28+
const length = pool.length;
29+
30+
if (r > length) {
31+
return;
32+
}
33+
34+
const indices = list(range(0, length, 1));
35+
const cycles = list(range(length, length - r, -1));
36+
37+
yield list(pick(pool, _take(indices, r)));
38+
39+
if (r === 0 || length === 0) {
40+
return;
41+
}
42+
43+
while (true) {
44+
let i = r;
45+
46+
while (i--) {
47+
--cycles[i];
48+
49+
if (cycles[i] === 0) {
50+
// Could be costly
51+
indices.push(indices.splice(i, 1)[0]);
52+
53+
cycles[i] = length - i;
54+
} else {
55+
const j = cycles[i];
56+
57+
[indices[i], indices[length - j]] = [indices[length - j], indices[i]];
58+
59+
yield list(pick(pool, _take(indices, r)));
60+
break;
61+
}
62+
}
63+
64+
if (i === -1) {
65+
return;
66+
}
67+
}
68+
}

‎test/src/api.js

-5
This file was deleted.

‎test/src/permutations.js

+43
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
import test from 'ava';
2+
3+
import {list} from '@iterable-iterator/list';
4+
import {range} from '@iterable-iterator/range';
5+
import {permutations} 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(permutations(iterable, r)), expected);
11+
};
12+
13+
macro.title = (title, iterable, r, expected) =>
14+
title ?? `permutations(${repr(iterable)}, ${r}) is ${repr(expected)}`;
15+
16+
test(macro, [], 1, []);
17+
test(macro, [], 0, [[]]);
18+
test(macro, [1, 2, 3], 0, [[]]);
19+
test(macro, [1, 2, 3], 4, []);
20+
21+
test(macro, 'ABCD', 2, [
22+
['A', 'B'],
23+
['A', 'C'],
24+
['A', 'D'],
25+
['B', 'A'],
26+
['B', 'C'],
27+
['B', 'D'],
28+
['C', 'A'],
29+
['C', 'B'],
30+
['C', 'D'],
31+
['D', 'A'],
32+
['D', 'B'],
33+
['D', 'C'],
34+
]);
35+
36+
test(macro, range(0, 3, 1), 3, [
37+
[0, 1, 2],
38+
[0, 2, 1],
39+
[1, 0, 2],
40+
[1, 2, 0],
41+
[2, 0, 1],
42+
[2, 1, 0],
43+
]);

‎yarn.lock

+10,107
Large diffs are not rendered by default.

0 commit comments

Comments
 (0)
Please sign in to comment.