Add support for forward (#100)
This commit is contained in:
parent
e9484080e7
commit
6b8d2970ac
@ -1,6 +1,11 @@
|
||||
import { moveOneLeft, moveAllLeft } from "./zindex";
|
||||
import { moveOneLeft, moveOneRight, moveAllLeft, moveAllRight } from "./zindex";
|
||||
|
||||
function expectMove(fn, elems, indices, equal) {
|
||||
function expectMove<T>(
|
||||
fn: (elements: T[], indicesToMove: number[]) => void,
|
||||
elems: T[],
|
||||
indices: number[],
|
||||
equal: T[]
|
||||
) {
|
||||
fn(elems, indices);
|
||||
expect(elems).toEqual(equal);
|
||||
}
|
||||
@ -17,6 +22,18 @@ it("should moveOneLeft", () => {
|
||||
expectMove(moveOneLeft, ["a", "b", "c", "d"], [1, 3], ["b", "a", "d", "c"]);
|
||||
});
|
||||
|
||||
it("should moveOneRight", () => {
|
||||
expectMove(moveOneRight, ["a", "b", "c", "d"], [1, 2], ["a", "d", "b", "c"]);
|
||||
expectMove(moveOneRight, ["a", "b", "c", "d"], [3], ["a", "b", "c", "d"]);
|
||||
expectMove(
|
||||
moveOneRight,
|
||||
["a", "b", "c", "d"],
|
||||
[0, 1, 2, 3],
|
||||
["a", "b", "c", "d"]
|
||||
);
|
||||
expectMove(moveOneRight, ["a", "b", "c", "d"], [0, 2], ["b", "a", "d", "c"]);
|
||||
});
|
||||
|
||||
it("should moveAllLeft", () => {
|
||||
expectMove(
|
||||
moveAllLeft,
|
||||
@ -49,3 +66,36 @@ it("should moveAllLeft", () => {
|
||||
["e", "f", "g", "a", "b", "c", "d"]
|
||||
);
|
||||
});
|
||||
|
||||
it("should moveAllRight", () => {
|
||||
expectMove(
|
||||
moveAllRight,
|
||||
["a", "b", "c", "d", "e", "f", "g"],
|
||||
[2, 5],
|
||||
["a", "b", "d", "e", "g", "c", "f"]
|
||||
);
|
||||
expectMove(
|
||||
moveAllRight,
|
||||
["a", "b", "c", "d", "e", "f", "g"],
|
||||
[5],
|
||||
["a", "b", "c", "d", "e", "g", "f"]
|
||||
);
|
||||
expectMove(
|
||||
moveAllRight,
|
||||
["a", "b", "c", "d", "e", "f", "g"],
|
||||
[0, 1, 2, 3, 4, 5, 6],
|
||||
["a", "b", "c", "d", "e", "f", "g"]
|
||||
);
|
||||
expectMove(
|
||||
moveAllRight,
|
||||
["a", "b", "c", "d", "e", "f", "g"],
|
||||
[0, 1, 2],
|
||||
["d", "e", "f", "g", "a", "b", "c"]
|
||||
);
|
||||
expectMove(
|
||||
moveAllRight,
|
||||
["a", "b", "c", "d", "e", "f", "g"],
|
||||
[4, 5, 6],
|
||||
["a", "b", "c", "d", "e", "f", "g"]
|
||||
);
|
||||
});
|
||||
|
@ -19,6 +19,24 @@ export function moveOneLeft<T>(elements: T[], indicesToMove: number[]) {
|
||||
});
|
||||
}
|
||||
|
||||
export function moveOneRight<T>(elements: T[], indicesToMove: number[]) {
|
||||
const reversedIndicesToMove = indicesToMove.sort(
|
||||
(a: number, b: number) => b - a
|
||||
);
|
||||
let isSorted = true;
|
||||
|
||||
// We go from right to left to avoid overriding the wrong elements
|
||||
reversedIndicesToMove.forEach((index, i) => {
|
||||
// We don't want to bubble the first elements that are sorted as they are
|
||||
// already in their correct position
|
||||
isSorted = isSorted && index === elements.length - i - 1;
|
||||
if (isSorted) {
|
||||
return;
|
||||
}
|
||||
swap(elements, index + 1, index);
|
||||
});
|
||||
}
|
||||
|
||||
// Let's go through an example
|
||||
// | |
|
||||
// [a, b, c, d, e, f, g]
|
||||
@ -95,3 +113,81 @@ export function moveAllLeft<T>(elements: T[], indicesToMove: number[]) {
|
||||
elements[i] = element;
|
||||
});
|
||||
}
|
||||
|
||||
// Let's go through an example
|
||||
// | |
|
||||
// [a, b, c, d, e, f, g]
|
||||
// -->
|
||||
// [a, b, d, e, g, c, f]
|
||||
//
|
||||
// We are going to override all the elements we want to move, so we keep them in an array
|
||||
// that we will restore at the end.
|
||||
// [c, f]
|
||||
//
|
||||
// From now on, we'll never read those values from the array anymore
|
||||
// |0 |1
|
||||
// [a, b, _, d, e, _, g]
|
||||
//
|
||||
// The idea is that we want to shift all the elements between the marker 0 and 1
|
||||
// by one slot to the left.
|
||||
//
|
||||
// |0 |1
|
||||
// [a, b, _, d, e, _, g]
|
||||
// <- <-
|
||||
//
|
||||
// which gives us
|
||||
//
|
||||
// |0 |1
|
||||
// [a, b, d, e, _, _, g]
|
||||
//
|
||||
// Now, we need to move all the elements from marker 1 to the end by two (not one)
|
||||
// slots to the left, which gives us
|
||||
//
|
||||
// |0 |1
|
||||
// [a, b, d, e, _, _, g]
|
||||
// ^------
|
||||
//
|
||||
// which gives us
|
||||
//
|
||||
// |0 |1
|
||||
// [a, b, d, e, g, _, _]
|
||||
//
|
||||
// At this point, we can fill back the rightmost elements with the array we saved at
|
||||
// the beggining
|
||||
//
|
||||
// |0 |1
|
||||
// [a, b, d, e, g, c, f]
|
||||
//
|
||||
// And we are done!
|
||||
export function moveAllRight<T>(elements: T[], indicesToMove: number[]) {
|
||||
const reversedIndicesToMove = indicesToMove.sort(
|
||||
(a: number, b: number) => b - a
|
||||
);
|
||||
|
||||
// Copy the elements to move
|
||||
const rightMostElements = reversedIndicesToMove.map(index => elements[index]);
|
||||
|
||||
indicesToMove = reversedIndicesToMove
|
||||
// We go from left to right to avoid overriding elements.
|
||||
.reverse()
|
||||
// We last element index for the final marker
|
||||
.concat([elements.length]);
|
||||
|
||||
indicesToMove.forEach((index, i) => {
|
||||
// We skip the first one as it is not paired with anything else
|
||||
if (i === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
// We go from the next marker to the left (i - 1) to the current one (index)
|
||||
for (let pos = indicesToMove[i - 1] + 1; pos < index; ++pos) {
|
||||
// We move by 1 the first time, 2 the second... So we can use the index i in the array
|
||||
elements[pos - i] = elements[pos];
|
||||
}
|
||||
});
|
||||
|
||||
// The final step
|
||||
rightMostElements.forEach((element, i) => {
|
||||
elements[elements.length - i - 1] = element;
|
||||
});
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user