Skip to content

Commit

Permalink
adding select logic
Browse files Browse the repository at this point in the history
  • Loading branch information
marrionluaka committed Jun 9, 2024
1 parent d95e11f commit 1f23d08
Show file tree
Hide file tree
Showing 2 changed files with 277 additions and 39 deletions.
236 changes: 211 additions & 25 deletions src/index.spec.ts
Original file line number Diff line number Diff line change
@@ -1,37 +1,223 @@
import { helloWorld, goodBye, howAreYou } from "../src/index";
import { select, selectAll } from ".";

describe("Hello World Function", () => {
it("should be a function", () => {
expect(typeof helloWorld).toBe("function");
});
describe("multiselect", () => {
let indices: number[];
let selectedIndex: number;
let selectedIndices: number[];

it("should return the hello world message", () => {
const expected = "Hello World from my example modern npm package!";
const actual = helloWorld();
expect(actual).toBe(expected);
beforeEach(() => {
indices = [...Array(7).keys()];
selectedIndex = 0;
selectedIndices = [0];
});
});

describe("Goodbye Function", () => {
it("should be a function", () => {
expect(typeof goodBye).toBe("function");
describe("select", () => {
it("should select an index and add it to the list of selected indices", () => {
expect(select(selectedIndices, selectedIndex, 2)).toEqual([2, [0, 2]]);
});

it("should remove an index from the list of selected indices", () => {
const allIndices = selectAll({
selectedIds: selectedIndices,
selectedId: selectedIndex,
ids: indices,
id: 3,
});

expect(select(allIndices, selectedIndex, 2)).toEqual([3, [0, 1, 3]]);
});

it("should remove an index even when it is the only index in the selected indices", () => {
expect(select(selectedIndices, selectedIndex, 0)).toEqual([0, []]);
});
});

it("should return the goodbye message", () => {
const expected = "Goodbye from my example modern npm package!";
const actual = goodBye();
expect(actual).toBe(expected);
describe("selectAll", () => {
beforeEach(() => {
selectedIndices = selectAll({
selectedIds: selectedIndices,
selectedId: selectedIndex,
ids: indices,
id: 4,
});
});

it("should select multiple indices given a range", () => {
expect(selectedIndices).toEqual([0, 1, 2, 3, 4]);
});

it("should select multiple indices starting from the current index after removing an index from the list of selected indices", () => {
const [nextSelectedIndex, nextSelectedIndices] = select(
selectedIndices,
selectedIndex,
2
);
expect(nextSelectedIndices).toEqual([0, 1, 3, 4]);

selectedIndices = selectAll({
selectedIds: nextSelectedIndices,
selectedId: nextSelectedIndex,
ids: indices,
id: 5,
});
expect(selectedIndices).toEqual([0, 1, 3, 4, 5]);
});

it("should select multiple indices starting from the next selected index after removing current selected index", () => {
let [nextIndex, nextIndices] = select(selectedIndices, selectedIndex, 4);
[nextIndex, nextIndices] = select(nextIndices, nextIndex, 4);
expect(nextIndices).toEqual([0, 1, 2, 3, 4]);

selectedIndices = selectAll({
selectedIds: nextIndices,
selectedId: nextIndex,
ids: indices,
id: 5,
});
expect(selectedIndices).toEqual([4, 5]);
});

it("should select multiple indices starting from the previous selected index after removing current selected index", () => {
// remove a single index
let [nextIndex, nextIndices] = select(selectedIndices, selectedIndex, 2);
expect(nextIndices).toEqual([0, 1, 3, 4]);

// remove the currently selected index
[nextIndex, nextIndices] = select(nextIndices, nextIndex, 4);
[nextIndex, nextIndices] = select(nextIndices, nextIndex, 4);
expect(nextIndices).toEqual([0, 1, 3, 4]);

selectedIndices = selectAll({
selectedIds: nextIndices,
selectedId: nextIndex,
ids: indices,
id: 6,
});
expect(selectedIndices).toEqual([0, 1, 4, 5, 6]);
});

it("should select indices starting from the last selected index", () => {
const [nextSelectedIndex, nextSelectedIndices] = select(
selectedIndices,
selectedIndex,
2
);
expect(nextSelectedIndices).toEqual([0, 1, 3, 4]);

selectedIndices = selectAll({
selectedIds: nextSelectedIndices,
selectedId: nextSelectedIndex,
ids: indices,
id: 2,
});
expect(selectedIndices).toEqual([2, 3]);
});
});
});

describe("How Are You Function", () => {
it("should be a function", () => {
expect(typeof howAreYou).toBe("function");
describe("selectAll (with filtered subset of indices)", () => {
beforeEach(() => {
indices = indices.map((x) => x * 7);
selectedIndices = selectAll({
selectedIds: selectedIndices,
selectedId: selectedIndex,
ids: indices,
id: 28,
});
});

it("should select multiple indices given a range", () => {
expect(selectedIndices).toEqual([0, 7, 14, 21, 28]);
});

it("should select multiple indices starting from the current index after removing an index from the list of selected indices", () => {
const [nextSelectedIndex, nextSelectedIndices] = select(
selectedIndices,
selectedIndex,
14
);
expect(nextSelectedIndices).toEqual([0, 7, 21, 28]);

selectedIndices = selectAll({
selectedIds: nextSelectedIndices,
selectedId: nextSelectedIndex,
ids: indices,
id: 35,
});
expect(selectedIndices).toEqual([0, 7, 21, 28, 35]);
});

it("should select multiple indices starting from the next selected index after removing current selected index", () => {
let [nextIndex, nextIndices] = select(selectedIndices, selectedIndex, 28);
[nextIndex, nextIndices] = select(nextIndices, nextIndex, 28);
expect(nextIndices).toEqual([0, 7, 14, 21, 28]);

selectedIndices = selectAll({
selectedIds: nextIndices,
selectedId: nextIndex,
ids: indices,
id: 35,
});
expect(selectedIndices).toEqual([28, 35]);
});

it("should select multiple indices starting from the previous selected index after removing current selected index", () => {
// remove a single index
let [nextIndex, nextIndices] = select(selectedIndices, selectedIndex, 14);
expect(nextIndices).toEqual([0, 7, 21, 28]);

// remove the currently selected index
[nextIndex, nextIndices] = select(nextIndices, nextIndex, 28);
[nextIndex, nextIndices] = select(nextIndices, nextIndex, 28);
expect(nextIndices).toEqual([0, 7, 21, 28]);

selectedIndices = selectAll({
selectedIds: nextIndices,
selectedId: nextIndex,
ids: indices,
id: 42,
});
expect(selectedIndices).toEqual([0, 7, 28, 35, 42]);
});

it("should select indices starting from the last selected index", () => {
const [nextSelectedIndex, nextSelectedIndices] = select(
selectedIndices,
selectedIndex,
14
);
expect(nextSelectedIndices).toEqual([0, 7, 21, 28]);

selectedIndices = selectAll({
selectedIds: nextSelectedIndices,
selectedId: nextSelectedIndex,
ids: indices,
id: 14,
});

expect(selectedIndices).toEqual([14, 21]);
});
});

it("should return the how are you message", () => {
const expected = "How are you from my example modern npm package!!";
const actual = howAreYou();
expect(actual).toBe(expected);
it("should extend with a non-consecutive set", () => {
indices = indices.map((x) => x * 7).reverse();
selectedIndex = 42;
selectedIndices = [42];

selectedIndices = selectAll({
selectedIds: selectedIndices,
selectedId: selectedIndex,
ids: indices,
id: 28,
});
let [nextIndex, nextIndices] = select(selectedIndices, selectedIndex, 35);

selectedIndices = selectAll({
selectedIds: nextIndices,
selectedId: nextIndex,
ids: indices,
id: 14,
});

expect(selectedIndices).toEqual([42, 28, 21, 14]);
});
});
80 changes: 66 additions & 14 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -1,20 +1,72 @@
export function helloWorld() {
const message = "Hello World from my example modern npm package!";
return message;
type SelectAllParams<T> = {
selectedIds: T[];
selectedId: T;
ids: T[];
id: T;
};

export function select<T>(selectedIds: T[], selectedId: T, id: T): [T, T[]] {
if (!selectedIds.includes(id)) return [id, selectedIds.concat(id)];

if (selectedIds.length === 1)
return selectedIds.includes(id) ? [id, []] : [selectedId, selectedIds];

const pivotIndex = selectedIds.findIndex((x) => x === id);
const nextSelectedIndex =
selectedIds[pivotIndex + 1] ?? selectedIds[pivotIndex - 1] ?? id;
const nextSelectedIndices = selectedIds.filter((x) => x !== id);

return [nextSelectedIndex, nextSelectedIndices];
}

export function goodBye() {
const message = "Goodbye from my example modern npm package!";
return message;
export function selectAll<T>({
selectedIds,
selectedId,
ids,
id,
}: SelectAllParams<T>): T[] {
const reverseIndexLookup = (x: T) => ids.indexOf(x);
const [_index, _selectedIndex] = [id, selectedId].map(reverseIndexLookup);
const _selectedIndices = selectedIds.map(reverseIndexLookup);

if (selectedIds.length <= 1)
return _selectAll<T>(ids, _selectedIndex, _index);

const nonConsecutiveIndex = _getNonConsecutiveIndex(_selectedIndices);

if (nonConsecutiveIndex === -1)
return _selectAll<T>(ids, _selectedIndex, _index);

if (reverseIndexLookup(selectedId) > reverseIndexLookup(id)) {
// current selection extends backward to meet target
return ids.slice(_index, _selectedIndex + 1);
}

// select remaining indices
return selectedIds
.slice(0, nonConsecutiveIndex)
.concat(ids.slice(_selectedIndex, _index + 1));
}

export function howAreYou() {
const message = "How are you from my example modern npm package!!";
return message;
function _selectAll<T>(indices: T[], selectedIndex: number, index: number) {
if (selectedIndex > index) {
// current selection extends backward to meet target
return indices.slice(index, selectedIndex + 1);
}

// current selection extends forward to meet target
return indices.slice(selectedIndex, index + 1);
}

export default {
helloWorld,
goodBye,
howAreYou,
};
function _getNonConsecutiveIndex(selectedIndices: number[]) {
let nonConsecutiveIndex = -1;

for (let i = 1, len = selectedIndices.length; i < len; i++) {
const [a, b] = [selectedIndices[i - 1], selectedIndices[i]];
if (a > b || Math.abs(a - b) > 1) {
nonConsecutiveIndex = i;
}
}

return nonConsecutiveIndex;
}

0 comments on commit 1f23d08

Please sign in to comment.