Skip to content

Commit 5ae305c

Browse files
✨ feat: Add rotate_left and rotate_right.
Fixes #44.
1 parent 855e416 commit 5ae305c

File tree

6 files changed

+152
-0
lines changed

6 files changed

+152
-0
lines changed

src/_rotate_left.js

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import assert from 'assert';
2+
import Node from './Node.js';
3+
4+
/**
5+
* Rotate list to the left n steps. The parameter n must be positive.
6+
*
7+
* @param {Node} x The current first node.
8+
* @param {number} n MUST be positive.
9+
* @return {Node} The new first node.
10+
*/
11+
export default function _rotate_left(x, n) {
12+
assert(Number.isInteger(n));
13+
assert(n > 0);
14+
assert(x instanceof Node);
15+
do {
16+
x = x.prev;
17+
} while (--n);
18+
19+
return x;
20+
}

src/_rotate_right.js

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import assert from 'assert';
2+
import Node from './Node.js';
3+
4+
/**
5+
* Rotate list to the right n steps. The parameter n must be positive.
6+
*
7+
* @param {Node} x The current first node.
8+
* @param {number} n MUST be positive.
9+
* @return {Node} The new first node.
10+
*/
11+
export default function _rotate_right(x, n) {
12+
assert(Number.isInteger(n));
13+
assert(n > 0);
14+
assert(x instanceof Node);
15+
do {
16+
x = x.next;
17+
} while (--n);
18+
19+
return x;
20+
}

src/index.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ export {default as _iter_fast} from './_iter_fast.js';
66
export {default as _len} from './_len.js';
77
export {default as _pop} from './_pop.js';
88
export {default as _remove} from './_remove.js';
9+
export {default as _rotate_left} from './_rotate_left.js';
10+
export {default as _rotate_right} from './_rotate_right.js';
911
export {default as _shift} from './_shift.js';
1012
export {default as concat} from './concat.js';
1113
export {default as empty} from './empty.js';
@@ -14,6 +16,8 @@ export {default as iter} from './iter.js';
1416
export {default as len} from './len.js';
1517
export {default as pop} from './pop.js';
1618
export {default as push} from './push.js';
19+
export {default as rotate_left} from './rotate_left.js';
20+
export {default as rotate_right} from './rotate_right.js';
1721
export {default as shift} from './shift.js';
1822
export {default as unshift} from './unshift.js';
1923
export {default as values} from './values.js';

src/rotate_left.js

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
import assert from 'assert';
2+
import Node from './Node.js';
3+
import rotate_right from './rotate_right.js';
4+
5+
/**
6+
* Do nothing if x is empty or n is zero.
7+
* Rotate left n steps if n is positive.
8+
* Rotate right n steps if n is negative.
9+
*
10+
* @param {Node} x The current first node.
11+
* @param {number} n
12+
* @return {Node} The new first node.
13+
*/
14+
const rotate_left = (x, n) => {
15+
assert(x === null || x instanceof Node);
16+
return rotate_right(x, -n);
17+
};
18+
19+
export default rotate_left;

src/rotate_right.js

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
import assert from 'assert';
2+
import Node from './Node.js';
3+
import _rotate_left from './_rotate_left.js';
4+
import _rotate_right from './_rotate_right.js';
5+
6+
/**
7+
* Do nothing if x is empty or n is zero.
8+
* Rotate right n steps if n is positive.
9+
* Rotate left n steps if n is negative.
10+
*
11+
* @param {Node} x The current first node.
12+
* @param {number} n
13+
* @return {Node} The new first node.
14+
*/
15+
export default function rotate_right(x, n) {
16+
assert(Number.isInteger(n));
17+
if (x === null) return null;
18+
assert(x instanceof Node);
19+
if (n === 0) return x;
20+
return n > 0 ? _rotate_right(x, n) : _rotate_left(x, -n);
21+
}

test/src/rotate.js

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
import test from 'ava';
2+
3+
import {list, range} from '@aureooms/js-itertools';
4+
5+
import {str} from './_fixtures.js';
6+
7+
import {from, rotate_left, rotate_right, len, values} from '../../src/index.js';
8+
9+
const toArray = (first) => list(values(first));
10+
11+
const immutability = (t, input, n) => {
12+
const x = from(input);
13+
const y = rotate_left(x, n);
14+
const z = rotate_right(y, n);
15+
const w = rotate_left(y, len(x) - n);
16+
17+
t.is(z, x);
18+
t.deepEqual(toArray(z), toArray(x));
19+
t.is(w, x);
20+
t.deepEqual(toArray(w), toArray(x));
21+
};
22+
23+
immutability.title = (title, input, n) =>
24+
title || `immutability (${str(input)}, ${n})`;
25+
26+
test(immutability, [], 0);
27+
test(immutability, [], -1);
28+
test(immutability, [], 1);
29+
test(immutability, [], -100);
30+
test(immutability, [], 100);
31+
test(immutability, 'abc', 0);
32+
test(immutability, 'abc', -1);
33+
test(immutability, 'abc', 1);
34+
test(immutability, 'abc', -100);
35+
test(immutability, 'abc', 100);
36+
test(immutability, list(range(1000)), 0);
37+
test(immutability, list(range(1000)), -1);
38+
test(immutability, list(range(1000)), 1);
39+
test(immutability, list(range(1000)), -100);
40+
test(immutability, list(range(1000)), 100);
41+
42+
const mutability = (t, rotate, input, n, output) => {
43+
const expected = list(output);
44+
const x = from(input);
45+
const y = rotate(x, n);
46+
const actual = toArray(y);
47+
t.deepEqual(actual, expected);
48+
};
49+
50+
mutability.title = (title, rotate, input, n, output) =>
51+
title || `mutability ${rotate.name}(${str(input)}, ${n}) = ${str(output)}`;
52+
53+
test(mutability, rotate_left, [], 0, []);
54+
test(mutability, rotate_left, [], -1, []);
55+
test(mutability, rotate_left, [], 1, []);
56+
test(mutability, rotate_left, [], -100, []);
57+
test(mutability, rotate_left, [], 100, []);
58+
test(mutability, rotate_right, [], 0, []);
59+
test(mutability, rotate_right, [], -1, []);
60+
test(mutability, rotate_right, [], 1, []);
61+
test(mutability, rotate_right, [], -100, []);
62+
test(mutability, rotate_right, [], 100, []);
63+
test(mutability, rotate_left, 'abc', 0, 'abc');
64+
test(mutability, rotate_left, 'abc', -1, 'bca');
65+
test(mutability, rotate_left, 'abc', 1, 'cab');
66+
test(mutability, rotate_right, 'abc', 0, 'abc');
67+
test(mutability, rotate_right, 'abc', -1, 'cab');
68+
test(mutability, rotate_right, 'abc', 1, 'bca');

0 commit comments

Comments
 (0)