Skip to content

Commit 5a16cb2

Browse files
♻️ refactor(combinations): Extract indices generator.
1 parent 866c09c commit 5a16cb2

File tree

2 files changed

+49
-38
lines changed

2 files changed

+49
-38
lines changed

src/_combinations.js

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
import {list} from '@iterable-iterator/list';
2+
import {range} from '@iterable-iterator/range';
3+
4+
/**
5+
* Yields all k-subsets of {0, 1, ..., n-1}.
6+
*
7+
* @param {number} n
8+
* @param {number} k
9+
* @returns {IterableIterator<number[]>}
10+
*/
11+
export default function* _combinations(n, k) {
12+
if (k > n) return;
13+
14+
const indices = list(range(0, k, 1));
15+
16+
yield indices;
17+
18+
while (true) {
19+
let i = k - 1;
20+
21+
// eslint-disable-next-line no-constant-condition
22+
while (true) {
23+
if (i < 0) return;
24+
25+
if (indices[i] !== i + n - k) {
26+
let pivot = ++indices[i];
27+
28+
for (++i; i < k; ++i) indices[i] = ++pivot;
29+
30+
break;
31+
}
32+
33+
--i;
34+
}
35+
36+
yield indices;
37+
}
38+
}

src/combinations.js

Lines changed: 11 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import {list} from '@iterable-iterator/list';
2-
import {pick} from '@iterable-iterator/map';
3-
import {range} from '@iterable-iterator/range';
2+
import {map, pick} from '@iterable-iterator/map';
3+
4+
import _combinations from './_combinations.js';
45

56
/**
67
* Yields all combinations of each possible choice of <code>r</code> elements
@@ -16,42 +17,14 @@ import {range} from '@iterable-iterator/range';
1617
*
1718
* @param {Iterable} iterable - The input iterable.
1819
* @param {number} r - The size of the combinations to generate.
19-
* @returns {IterableIterator}
20+
* @returns {IterableIterator<Array>}
2021
*/
21-
export default function* combinations(iterable, r) {
22+
const combinations = (iterable, r) => {
2223
const pool = list(iterable);
23-
const length = pool.length;
24-
25-
if (r > length) {
26-
return;
27-
}
28-
29-
const indices = list(range(0, r, 1));
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] !== i + length - r) {
43-
let pivot = ++indices[i];
44-
45-
for (++i; i < r; ++i) {
46-
indices[i] = ++pivot;
47-
}
48-
49-
break;
50-
}
51-
52-
--i;
53-
}
24+
return map(
25+
(indices) => list(pick(pool, indices)),
26+
_combinations(pool.length, r),
27+
);
28+
};
5429

55-
yield list(pick(pool, indices));
56-
}
57-
}
30+
export default combinations;

0 commit comments

Comments
 (0)