Write moveItem(array, from, to). It returns a new array in which the item at index from has moved, and the items between from and to have shifted over by one to make room, the way a list reorders when you drag an item to a new place.
After the move, the item is at index to of the new array, whether it moved down the list (to greater than from) or up.
Negative indexes count back from the end, as they do with at: -1 is the last item. If from or to isn't an integer, or points outside the array, throw a RangeError.
array itself never changes, and the result is always a new array, even when from and to are the same.
const list = ["a", "b", "c", "d"];
moveItem(list, 0, 2); // ["b", "c", "a", "d"]
moveItem(list, 3, 1); // ["a", "d", "b", "c"]
moveItem(list, 0, -1); // ["b", "c", "d", "a"]
moveItem(list, 4, 0); // throws a RangeError
list; // ["a", "b", "c", "d"]
expect(moveItem(["a", "b", "c", "d"], 0, 2)).toEqual(["b", "c", "a", "d"]);
expect(moveItem(["a", "b", "c", "d"], 1, 3)).toEqual(["a", "c", "d", "b"]);
expect(moveItem(["a", "b", "c", "d"], 3, 1)).toEqual(["a", "d", "b", "c"]);
expect(moveItem(["a", "b", "c", "d"], 2, 0)).toEqual(["c", "a", "b", "d"]);
const list = ["a", "b", "c", "d", "e"];
for (let from = 0; from < list.length; from++) {
for (let to = 0; to < list.length; to++) {
const moved = moveItem(list, from, to);
expect(moved).toHaveLength(5);
expect(moved[to]).toBe(list[from]);
expect(moved.filter((item) => item !== list[from])).toEqual(list.filter((item) => item !== list[from]));
}
}
const list = ["a", "b", "c"];
const moved = moveItem(list, 1, 1);
expect(moved).toEqual(["a", "b", "c"]);
expect(moved).not.toBe(list);
const list = ["a", "b", "c", "d"];
expect(moveItem(list, -1, 0)).toEqual(["d", "a", "b", "c"]);
expect(moveItem(list, 0, -1)).toEqual(["b", "c", "d", "a"]);
expect(moveItem(list, 1, -2)).toEqual(["a", "c", "b", "d"]);
const calls = [[["a", "b"], 2, 0], [["a", "b"], 0, 2], [["a", "b"], -3, 0], [["a", "b"], 0, -3], [[], 0, 0]];
for (const [list, from, to] of calls) {
let thrown;
try {
moveItem(list, from, to);
} catch (error) {
thrown = error;
}
// The page stops a loop that never ends with an InfiniteLoopError, which is a RangeError too, so report it here.
if (thrown?.name === "InfiniteLoopError") throw new Error("moveItem(" + JSON.stringify(list) + ", " + from + ", " + to + ") never finished: " + thrown.message);
expect(thrown).toBeInstanceOf(RangeError);
}
const list = ["a", "b"];
for (const [from, to] of [[0.5, 1], [0, NaN], ["1", 0]]) {
let thrown;
try {
moveItem(list, from, to);
} catch (error) {
thrown = error;
}
// The page stops a loop that never ends with an InfiniteLoopError, which is a RangeError too, so report it here.
if (thrown?.name === "InfiniteLoopError") throw new Error("moveItem(" + JSON.stringify(list) + ", " + JSON.stringify(from) + ", " + to + ") never finished: " + thrown.message);
expect(thrown).toBeInstanceOf(RangeError);
}
const first = { id: 1 };
const list = [first, { id: 2 }, { id: 3 }];
const moved = moveItem(list, 0, 2);
expect(list.map((item) => item.id)).toEqual([1, 2, 3]);
expect(moved.map((item) => item.id)).toEqual([2, 3, 1]);
expect(moved[2]).toBe(first);
Run tests runs every test on your code, here in your browser. The problem is solved when they all pass.
Ctrl + Enter runs the tests (⌘ + Enter on a Mac).
I'm here to help with Move an item in a list. I give hints, never the solution, so you get to solve it yourself. Ask for a hint, select code to ask about it, or press Ask Tuto why on a failing test.
Your first 3 answers need no account. for free to keep asking.