| export declare type Bucket<T> = T[]; | ||
| export declare type Buckets<T> = { | ||
| [key: number]: Bucket<T>; | ||
| }; | ||
| export declare type Accessor<T extends object> = (item: T) => number; | ||
| export declare function getSortedKeys<T>(buckets: Buckets<T>): number[]; | ||
| export declare function calculateItemsLeft<T>(buckets: Buckets<T>): number; | ||
| export declare function rowsAreEqual<T extends object | number>(rowA: T[], rowB: T[], accessor: T extends object ? Accessor<T> : undefined): boolean; | ||
| export declare function groupItemsByValue<T extends object | number>(items: T[], accessor: T extends object ? Accessor<T> : undefined): Buckets<T>; | ||
| export declare function getFillableItem<T>(buckets: Buckets<T>, maxKey: number): number; | ||
| export declare function buildGridFromBuckets<T extends object | number>({ buckets, columns, accessor, }: { | ||
| buckets: Buckets<T>; | ||
| columns: number; | ||
| accessor: T extends object ? Accessor<T> : undefined; | ||
| }): T[][]; | ||
| export declare function gridSort<T extends object | number>({ items, columns, accessor, }: { | ||
| items: T[]; | ||
| columns?: number; | ||
| accessor: T extends object ? Accessor<T> : never; | ||
| }): T[][]; |
| const keysOf = (object) => Object.keys(object); | ||
| const itemsInBucket = (buckets, key) => { var _a; return ((_a = buckets[key]) === null || _a === void 0 ? void 0 : _a.length) || 0 > 0; }; | ||
| const rowQuantity = (row, accessor) => row.reduce((acc, item) => { | ||
| if (accessor && typeof item === "object") { | ||
| const value = accessor(item); | ||
| return acc + value; | ||
| } | ||
| if (typeof item === "number") { | ||
| return acc + item; | ||
| } | ||
| return acc; | ||
| }, 0); | ||
| export function getSortedKeys(buckets) { | ||
| return keysOf(buckets).sort((a, z) => z - a); | ||
| } | ||
| export function calculateItemsLeft(buckets) { | ||
| return Object.values(buckets).reduce((acc, bucket) => acc + bucket.length, 0); | ||
| } | ||
| export function rowsAreEqual(rowA, rowB, accessor) { | ||
| return rowA.every((value, index) => { | ||
| let itemA = value; | ||
| let itemB = rowB[index]; | ||
| if (accessor && typeof itemA === "object" && typeof itemB === "object") { | ||
| return accessor(itemA) === accessor(itemB); | ||
| } | ||
| return itemA === itemB; | ||
| }); | ||
| } | ||
| export function groupItemsByValue(items, accessor) { | ||
| const groups = {}; | ||
| for (const item of items) { | ||
| let key; | ||
| if (accessor && typeof item === "object") { | ||
| key = accessor(item); | ||
| } | ||
| else if (typeof item === "number") { | ||
| key = item; | ||
| } | ||
| if (key === undefined) | ||
| continue; | ||
| const group = groups[key]; | ||
| if (group && Array.isArray(group)) { | ||
| group.push(item); | ||
| } | ||
| else { | ||
| groups[key] = [item]; | ||
| } | ||
| } | ||
| return groups; | ||
| } | ||
| export function getFillableItem(buckets, maxKey) { | ||
| let currentBiggestKey = 0; | ||
| const sortedKeys = getSortedKeys(buckets); | ||
| for (const key of sortedKeys) { | ||
| if (itemsInBucket(buckets, key) && | ||
| key > currentBiggestKey && | ||
| key <= maxKey) { | ||
| currentBiggestKey = key; | ||
| } | ||
| } | ||
| return currentBiggestKey; | ||
| } | ||
| export function buildGridFromBuckets({ buckets, columns, accessor, }) { | ||
| const grid = []; | ||
| let itemsLeft; | ||
| while ((itemsLeft = calculateItemsLeft(buckets)) > 0) { | ||
| const row = []; | ||
| let key; | ||
| while ((key = getFillableItem(buckets, columns - rowQuantity(row, accessor))) && | ||
| rowQuantity(row, accessor) < columns && | ||
| itemsLeft >= 1) { | ||
| const bucket = buckets[key]; | ||
| if (!bucket) | ||
| continue; | ||
| const item = bucket.shift(); | ||
| if (!item) | ||
| break; | ||
| row.push(item); | ||
| } | ||
| // randomize current row if previous row has same layout | ||
| const previousRow = grid[grid.length - 1]; | ||
| if (previousRow && rowsAreEqual(row, previousRow, accessor)) { | ||
| row.reverse(); | ||
| } | ||
| grid.push(row); | ||
| } | ||
| return grid; | ||
| } | ||
| export function gridSort({ items, columns = 4, accessor, }) { | ||
| const buckets = groupItemsByValue(items, accessor); | ||
| return buildGridFromBuckets({ buckets, columns, accessor }); | ||
| } |
| export { gridSort } from "./gridSort.js"; |
| export { gridSort } from "./gridSort.js"; |
+148
| export type Bucket<T> = T[]; | ||
| export type Buckets<T> = { [key: number]: Bucket<T> }; | ||
| export type Accessor<T extends object> = (item: T) => number; | ||
| const keysOf = <T extends object>(object: T) => | ||
| Object.keys(object) as (keyof typeof object)[]; | ||
| const itemsInBucket = <T extends unknown>( | ||
| buckets: Buckets<T>, | ||
| key: keyof Buckets<T> | ||
| ) => buckets[key]?.length || 0 > 0; | ||
| const rowQuantity = <T extends object | number>( | ||
| row: T[], | ||
| accessor: T extends object ? Accessor<T> : undefined | ||
| ) => | ||
| row.reduce((acc, item) => { | ||
| if (accessor && typeof item === "object") { | ||
| const value = accessor(item); | ||
| return acc + value; | ||
| } | ||
| if (typeof item === "number") { | ||
| return acc + item; | ||
| } | ||
| return acc; | ||
| }, 0); | ||
| export function getSortedKeys<T>(buckets: Buckets<T>) { | ||
| return keysOf(buckets).sort((a, z) => z - a); | ||
| } | ||
| export function calculateItemsLeft<T>(buckets: Buckets<T>) { | ||
| return Object.values(buckets).reduce((acc, bucket) => acc + bucket.length, 0); | ||
| } | ||
| export function rowsAreEqual<T extends object | number>( | ||
| rowA: T[], | ||
| rowB: T[], | ||
| accessor: T extends object ? Accessor<T> : undefined | ||
| ) { | ||
| return rowA.every((value, index) => { | ||
| let itemA = value; | ||
| let itemB = rowB[index] as T; | ||
| if (accessor && typeof itemA === "object" && typeof itemB === "object") { | ||
| return accessor(itemA) === accessor(itemB); | ||
| } | ||
| return itemA === itemB; | ||
| }); | ||
| } | ||
| export function groupItemsByValue<T extends object | number>( | ||
| items: T[], | ||
| accessor: T extends object ? Accessor<T> : undefined | ||
| ) { | ||
| const groups: Buckets<T> = {}; | ||
| for (const item of items) { | ||
| let key: number | undefined; | ||
| if (accessor && typeof item === "object") { | ||
| key = accessor(item); | ||
| } else if (typeof item === "number") { | ||
| key = item; | ||
| } | ||
| if (key === undefined) continue; | ||
| const group = groups[key]; | ||
| if (group && Array.isArray(group)) { | ||
| group.push(item); | ||
| } else { | ||
| groups[key] = [item]; | ||
| } | ||
| } | ||
| return groups; | ||
| } | ||
| export function getFillableItem<T>(buckets: Buckets<T>, maxKey: number) { | ||
| let currentBiggestKey = 0; | ||
| const sortedKeys = getSortedKeys(buckets); | ||
| for (const key of sortedKeys) { | ||
| if ( | ||
| itemsInBucket(buckets, key) && | ||
| key > currentBiggestKey && | ||
| key <= maxKey | ||
| ) { | ||
| currentBiggestKey = key; | ||
| } | ||
| } | ||
| return currentBiggestKey; | ||
| } | ||
| export function buildGridFromBuckets<T extends object | number>({ | ||
| buckets, | ||
| columns, | ||
| accessor, | ||
| }: { | ||
| buckets: Buckets<T>; | ||
| columns: number; | ||
| accessor: T extends object ? Accessor<T> : undefined; | ||
| }) { | ||
| const grid = []; | ||
| let itemsLeft: number; | ||
| while ((itemsLeft = calculateItemsLeft(buckets)) > 0) { | ||
| const row: T[] = []; | ||
| let key: number; | ||
| while ( | ||
| (key = getFillableItem(buckets, columns - rowQuantity(row, accessor))) && | ||
| rowQuantity(row, accessor) < columns && | ||
| itemsLeft >= 1 | ||
| ) { | ||
| const bucket = buckets[key]; | ||
| if (!bucket) continue; | ||
| const item = bucket.shift(); | ||
| if (!item) break; | ||
| row.push(item); | ||
| } | ||
| // randomize current row if previous row has same layout | ||
| const previousRow = grid[grid.length - 1]; | ||
| if (previousRow && rowsAreEqual(row, previousRow, accessor)) { | ||
| row.reverse(); | ||
| } | ||
| grid.push(row); | ||
| } | ||
| return grid; | ||
| } | ||
| export function gridSort<T extends object | number>({ | ||
| items, | ||
| columns = 4, | ||
| accessor, | ||
| }: { | ||
| items: T[]; | ||
| columns?: number; | ||
| accessor: T extends object ? Accessor<T> : never; | ||
| }) { | ||
| const buckets = groupItemsByValue(items, accessor); | ||
| return buildGridFromBuckets({ buckets, columns, accessor }); | ||
| } |
| export { gridSort } from "./gridSort.js"; |
+209
| import { test } from "uvu"; | ||
| import * as assert from "uvu/assert"; | ||
| import type { Buckets } from "../lib/gridSort.js"; | ||
| import { | ||
| buildGridFromBuckets, | ||
| getFillableItem, | ||
| getSortedKeys, | ||
| gridSort, | ||
| groupItemsByValue, | ||
| rowsAreEqual, | ||
| } from "../lib/gridSort.js"; | ||
| test("sorts object keys numerically in descending order", () => { | ||
| const buckets = { 1: [1, 1, 1], 2: [2, 2], 3: [3, 3] }; | ||
| assert.equal(getSortedKeys(buckets), [3, 2, 1].map(String)); | ||
| }); | ||
| test("gets best candidate for filling a column", () => { | ||
| const bucketsA = { 1: [1, 1, 1], 2: [2, 2], 3: [3, 3] }; | ||
| assert.equal(getFillableItem(bucketsA, 4), "3"); | ||
| const bucketsB = { 1: [1, 1, 1], 2: [2, 2], 3: [3, 3] }; | ||
| assert.equal(getFillableItem(bucketsB, 1), "1"); | ||
| const bucketsC = { 1: [1, 1, 1], 2: [2, 2], 3: [3, 3] }; | ||
| assert.equal(getFillableItem(bucketsC, 2), "2"); | ||
| const bucketsD = { 1: [1, 1, 1], 2: [2, 2], 3: [] }; | ||
| assert.equal(getFillableItem(bucketsD, 4), "2"); | ||
| const bucketsE = { 1: [1, 1, 1], 2: [], 3: [] }; | ||
| assert.equal(getFillableItem(bucketsE, 4), "1"); | ||
| const bucketsF = { 1: [1, 1, 1], 2: [2, 2], 3: [3, 3] }; | ||
| assert.equal(getFillableItem(bucketsF, 2), "2"); | ||
| const bucketsG = { 1: [1, 1, 1], 2: [2, 2], 3: [3, 3] }; | ||
| assert.equal(getFillableItem(bucketsG, 1), "1"); | ||
| }); | ||
| test("rows equality", () => { | ||
| const [rowA, rowB] = [ | ||
| [ | ||
| { id: "1", ratio: 3 }, | ||
| { id: "2", ratio: 1 }, | ||
| ], | ||
| [ | ||
| { id: "8", ratio: 3 }, | ||
| { id: "5", ratio: 1 }, | ||
| ], | ||
| ]; | ||
| const accessor = (item: typeof rowA[number]) => item.ratio; | ||
| assert.ok(rowsAreEqual(rowA, rowB, accessor)); | ||
| assert.not.ok(rowsAreEqual(rowA, rowB.reverse(), accessor)); | ||
| }); | ||
| test("it sorts bucket of numbers", () => { | ||
| const buckets = { | ||
| 1: [1, 1, 1, 1, 1], | ||
| 2: [2, 2], | ||
| 3: [3, 3], | ||
| } as Buckets<number>; | ||
| const sorted = buildGridFromBuckets({ | ||
| buckets, | ||
| columns: 4, | ||
| accessor: undefined, | ||
| }); | ||
| const expected = [ | ||
| [3, 1], | ||
| [1, 3], | ||
| [2, 2], | ||
| [1, 1, 1], | ||
| ]; | ||
| assert.equal(sorted, expected); | ||
| }); | ||
| test("it builds buckets from array of items", () => { | ||
| const items = [ | ||
| { id: "1", ratio: 3 }, | ||
| { id: "2", ratio: 1 }, | ||
| { id: "3", ratio: 2 }, | ||
| { id: "4", ratio: 2 }, | ||
| { id: "5", ratio: 1 }, | ||
| { id: "7", ratio: 1 }, | ||
| { id: "8", ratio: 3 }, | ||
| ]; | ||
| const itemsByValue = groupItemsByValue(items, (item) => item.ratio); | ||
| assert.equal(itemsByValue, { | ||
| 1: [ | ||
| { id: "2", ratio: 1 }, | ||
| { id: "5", ratio: 1 }, | ||
| { id: "7", ratio: 1 }, | ||
| ], | ||
| 2: [ | ||
| { id: "3", ratio: 2 }, | ||
| { id: "4", ratio: 2 }, | ||
| ], | ||
| 3: [ | ||
| { id: "1", ratio: 3 }, | ||
| { id: "8", ratio: 3 }, | ||
| ], | ||
| }); | ||
| }); | ||
| test("it sorts bucket of objects", () => { | ||
| const items = [ | ||
| { id: "1", ratio: 3 }, | ||
| { id: "2", ratio: 1 }, | ||
| { id: "3", ratio: 2 }, | ||
| { id: "4", ratio: 2 }, | ||
| { id: "5", ratio: 1 }, | ||
| { id: "7", ratio: 1 }, | ||
| { id: "8", ratio: 3 }, | ||
| ]; | ||
| const accessor = (item: typeof items[number]) => item.ratio; | ||
| const itemsByValue = groupItemsByValue(items, accessor); | ||
| const sorted = buildGridFromBuckets({ | ||
| buckets: itemsByValue, | ||
| columns: 4, | ||
| accessor, | ||
| }); | ||
| const expected = [ | ||
| [ | ||
| { id: "1", ratio: 3 }, | ||
| { id: "2", ratio: 1 }, | ||
| ], | ||
| [ | ||
| { id: "5", ratio: 1 }, | ||
| { id: "8", ratio: 3 }, | ||
| ], | ||
| [ | ||
| { id: "3", ratio: 2 }, | ||
| { id: "4", ratio: 2 }, | ||
| ], | ||
| [{ id: "7", ratio: 1 }], | ||
| ]; | ||
| assert.equal(sorted, expected); | ||
| }); | ||
| test("it sorts bucket of objects with different columns", () => { | ||
| const items = [ | ||
| { id: "1", ratio: 3 }, | ||
| { id: "2", ratio: 1 }, | ||
| { id: "3", ratio: 2 }, | ||
| { id: "4", ratio: 2 }, | ||
| { id: "5", ratio: 1 }, | ||
| { id: "7", ratio: 1 }, | ||
| { id: "8", ratio: 3 }, | ||
| ]; | ||
| const accessor = (item: typeof items[number]) => item.ratio; | ||
| const itemsByValue = groupItemsByValue(items, accessor); | ||
| const sorted = buildGridFromBuckets({ | ||
| buckets: itemsByValue, | ||
| columns: 5, | ||
| accessor, | ||
| }); | ||
| const expected = [ | ||
| [ | ||
| { id: "1", ratio: 3 }, | ||
| { id: "3", ratio: 2 }, | ||
| ], | ||
| [ | ||
| { id: "4", ratio: 2 }, | ||
| { id: "8", ratio: 3 }, | ||
| ], | ||
| [ | ||
| { id: "2", ratio: 1 }, | ||
| { id: "5", ratio: 1 }, | ||
| { id: "7", ratio: 1 }, | ||
| ], | ||
| ]; | ||
| assert.equal(sorted, expected); | ||
| }); | ||
| test("it sorts an array of items into a grid", () => { | ||
| const items = [ | ||
| { id: "1", ratio: 3 }, | ||
| { id: "2", ratio: 1 }, | ||
| { id: "3", ratio: 2 }, | ||
| { id: "4", ratio: 2 }, | ||
| { id: "5", ratio: 1 }, | ||
| { id: "7", ratio: 1 }, | ||
| { id: "8", ratio: 3 }, | ||
| ]; | ||
| const accessor = (item: typeof items[number]) => item.ratio; | ||
| const sorted = gridSort({ | ||
| items, | ||
| columns: 5, | ||
| accessor, | ||
| }); | ||
| const expected = [ | ||
| [ | ||
| { id: "1", ratio: 3 }, | ||
| { id: "3", ratio: 2 }, | ||
| ], | ||
| [ | ||
| { id: "4", ratio: 2 }, | ||
| { id: "8", ratio: 3 }, | ||
| ], | ||
| [ | ||
| { id: "2", ratio: 1 }, | ||
| { id: "5", ratio: 1 }, | ||
| { id: "7", ratio: 1 }, | ||
| ], | ||
| ]; | ||
| assert.equal(sorted, expected); | ||
| }); | ||
| test.run(); |
| { | ||
| "compilerOptions": { | ||
| "declaration": true, | ||
| "esModuleInterop": true, | ||
| "forceConsistentCasingInFileNames": true, | ||
| "lib": ["ESNext"], | ||
| "module": "ES2020", | ||
| "moduleResolution": "node", | ||
| "noFallthroughCasesInSwitch": true, | ||
| "noImplicitAny": true, | ||
| "noImplicitOverride": true, | ||
| "noImplicitReturns": true, | ||
| "noImplicitThis": true, | ||
| "noPropertyAccessFromIndexSignature": true, | ||
| "noUncheckedIndexedAccess": true, | ||
| "noUnusedLocals": true, | ||
| "noUnusedParameters": true, | ||
| "outDir": "./lib", | ||
| "strict": true, | ||
| "strictBindCallApply": true, | ||
| "strictFunctionTypes": true, | ||
| "strictNullChecks": true, | ||
| "strictPropertyInitialization": true, | ||
| "skipLibCheck": true, | ||
| "target": "ES2015", | ||
| }, | ||
| "include": ["src"] | ||
| } |
+9
-3
| { | ||
| "name": "grid-sort", | ||
| "version": "1.0.0", | ||
| "version": "2.0.0", | ||
| "description": "Sort objects in a two dimensional array to compose grids based on a condition", | ||
| "main": "index.js", | ||
| "exports": "./lib/index.js", | ||
| "author": "Luis Adame Rodríguez <luis@adame.dev>", | ||
@@ -10,7 +10,13 @@ "license": "MIT", | ||
| "devDependencies": { | ||
| "ts-node": "^10.2.1", | ||
| "typescript": "^4.3.5", | ||
| "uvu": "^0.5.1" | ||
| }, | ||
| "engines": { | ||
| "node": "^12.20.0 || ^14.13.1 || >=16.0.0" | ||
| }, | ||
| "scripts": { | ||
| "test": "node tests" | ||
| "test": "node --experimental-loader ts-node/esm node_modules/uvu/bin.js tests", | ||
| "tsc": "tsc" | ||
| } | ||
| } |
-90
| export const getSortedKeys = (buckets) => | ||
| Object.keys(buckets).sort((a, z) => z - a); | ||
| const calculateItemsLeft = (buckets) => | ||
| Object.values(buckets).reduce((acc, bucket) => acc + bucket.length, 0); | ||
| const itemsInBucket = (buckets, key) => buckets[key].length > 0; | ||
| const rowQuantity = (row, accessor) => | ||
| row.reduce((acc, item) => { | ||
| const value = accessor ? accessor(item) : item; | ||
| return acc + value; | ||
| }, 0); | ||
| export const rowsAreEqual = (rowA, rowB, accessor) => | ||
| rowA.every((value, index) => { | ||
| let itemA = value; | ||
| let itemB = rowB[index]; | ||
| if (accessor) { | ||
| itemA = accessor(itemA); | ||
| itemB = accessor(itemB); | ||
| } | ||
| return itemA === itemB; | ||
| }); | ||
| /** | ||
| * @param {Array<*>} items | ||
| * @param {(item) => * | undefined} accessor | ||
| */ | ||
| export function groupItemsByValue(items, accessor) { | ||
| const groups = {}; | ||
| for (const item of items) { | ||
| let key = item; | ||
| if (accessor) { | ||
| key = accessor(item); | ||
| } | ||
| groups[key] = groups[key] ? [...groups[key], item] : [item]; | ||
| } | ||
| return groups; | ||
| } | ||
| export const getFillableItem = (buckets, maxKey) => { | ||
| let currentBiggestKey = 0; | ||
| const sortedKeys = getSortedKeys(buckets); | ||
| for (const key of sortedKeys) { | ||
| if ( | ||
| itemsInBucket(buckets, key) && | ||
| key > currentBiggestKey && | ||
| key <= maxKey | ||
| ) { | ||
| currentBiggestKey = key; | ||
| } | ||
| } | ||
| return currentBiggestKey; | ||
| }; | ||
| /** | ||
| * | ||
| * @param {Object<number, Array<*>>} buckets | ||
| * @param {Number} columns | ||
| * @param {(item) => *} accessor | ||
| */ | ||
| export function makeGrid(buckets, columns = 4, accessor) { | ||
| const grid = []; | ||
| let itemsLeft; | ||
| while ((itemsLeft = calculateItemsLeft(buckets)) > 0) { | ||
| const row = []; | ||
| let key; | ||
| while ( | ||
| (key = getFillableItem(buckets, columns - rowQuantity(row, accessor))) && | ||
| rowQuantity(row, accessor) < columns && | ||
| itemsLeft >= 1 | ||
| ) { | ||
| row.push(buckets[key].shift()); | ||
| } | ||
| // randomize current row if previous row has same layout | ||
| const previousRow = grid[grid.length - 1]; | ||
| if (previousRow && rowsAreEqual(row, previousRow, accessor)) { | ||
| row.reverse(); | ||
| } | ||
| grid.push(row); | ||
| } | ||
| return grid; | ||
| } |
-146
| import { test } from "uvu"; | ||
| import * as assert from "uvu/assert"; | ||
| import { | ||
| getFillableItem, | ||
| getSortedKeys, | ||
| groupItemsByValue, | ||
| makeGrid, | ||
| rowsAreEqual, | ||
| } from "../index.js"; | ||
| test("getSortedKeys", () => { | ||
| const buckets = { 1: [1, 1, 1], 2: [2, 2], 3: [3, 3] }; | ||
| assert.equal(getSortedKeys(buckets), [3, 2, 1].map(String)); | ||
| }); | ||
| test("getFillableItem", () => { | ||
| const buckets = { 1: [1, 1, 1], 2: [2, 2], 3: [3, 3] }; | ||
| assert.equal(getFillableItem(buckets, 4), "3"); | ||
| }); | ||
| test("rowsAreEqual", () => { | ||
| let rowA = [ | ||
| { id: "1", ratio: 3 }, | ||
| { id: "2", ratio: 1 }, | ||
| ]; | ||
| let rowB = [ | ||
| { id: "8", ratio: 3 }, | ||
| { id: "5", ratio: 1 }, | ||
| ]; | ||
| const accessor = (item) => item.ratio; | ||
| assert.ok(rowsAreEqual(rowA, rowB, accessor)); | ||
| rowA = [ | ||
| { id: "1", ratio: 3 }, | ||
| { id: "2", ratio: 1 }, | ||
| ]; | ||
| rowB = [ | ||
| { id: "5", ratio: 1 }, | ||
| { id: "8", ratio: 3 }, | ||
| ]; | ||
| assert.not.ok(rowsAreEqual(rowA, rowB, accessor)); | ||
| }); | ||
| test("it sorts bucket of numbers", () => { | ||
| const buckets = { 1: [1, 1, 1, 1, 1], 2: [2, 2], 3: [3, 3] }; | ||
| const sorted = makeGrid(buckets); | ||
| const expected = [ | ||
| [3, 1], | ||
| [1, 3], | ||
| [2, 2], | ||
| [1, 1, 1], | ||
| ]; | ||
| assert.equal(sorted, expected); | ||
| }); | ||
| test("groupItemsByValue", () => { | ||
| const items = [ | ||
| { id: "1", ratio: 3 }, | ||
| { id: "2", ratio: 1 }, | ||
| { id: "3", ratio: 2 }, | ||
| { id: "4", ratio: 2 }, | ||
| { id: "5", ratio: 1 }, | ||
| { id: "7", ratio: 1 }, | ||
| { id: "8", ratio: 3 }, | ||
| ]; | ||
| const itemsByValue = groupItemsByValue(items, (item) => item.ratio); | ||
| assert.equal(itemsByValue, { | ||
| 1: [ | ||
| { id: "2", ratio: 1 }, | ||
| { id: "5", ratio: 1 }, | ||
| { id: "7", ratio: 1 }, | ||
| ], | ||
| 2: [ | ||
| { id: "3", ratio: 2 }, | ||
| { id: "4", ratio: 2 }, | ||
| ], | ||
| 3: [ | ||
| { id: "1", ratio: 3 }, | ||
| { id: "8", ratio: 3 }, | ||
| ], | ||
| }); | ||
| }); | ||
| test("it sorts bucket of objects", () => { | ||
| const items = [ | ||
| { id: "1", ratio: 3 }, | ||
| { id: "2", ratio: 1 }, | ||
| { id: "3", ratio: 2 }, | ||
| { id: "4", ratio: 2 }, | ||
| { id: "5", ratio: 1 }, | ||
| { id: "7", ratio: 1 }, | ||
| { id: "8", ratio: 3 }, | ||
| ]; | ||
| const accessor = (item) => item.ratio; | ||
| const itemsByValue = groupItemsByValue(items, accessor); | ||
| const sorted = makeGrid(itemsByValue, 4, accessor); | ||
| const expected = [ | ||
| [ | ||
| { id: "1", ratio: 3 }, | ||
| { id: "2", ratio: 1 }, | ||
| ], | ||
| [ | ||
| { id: "5", ratio: 1 }, | ||
| { id: "8", ratio: 3 }, | ||
| ], | ||
| [ | ||
| { id: "3", ratio: 2 }, | ||
| { id: "4", ratio: 2 }, | ||
| ], | ||
| [{ id: "7", ratio: 1 }], | ||
| ]; | ||
| assert.equal(sorted, expected); | ||
| }); | ||
| test("it sorts bucket of objects with different columns", () => { | ||
| const items = [ | ||
| { id: "1", ratio: 3 }, | ||
| { id: "2", ratio: 1 }, | ||
| { id: "3", ratio: 2 }, | ||
| { id: "4", ratio: 2 }, | ||
| { id: "5", ratio: 1 }, | ||
| { id: "7", ratio: 1 }, | ||
| { id: "8", ratio: 3 }, | ||
| ]; | ||
| const accessor = (item) => item.ratio; | ||
| const itemsByValue = groupItemsByValue(items, accessor); | ||
| const sorted = makeGrid(itemsByValue, 5, accessor); | ||
| const expected = [ | ||
| [ | ||
| { id: "1", ratio: 3 }, | ||
| { id: "3", ratio: 2 }, | ||
| ], | ||
| [ | ||
| { id: "4", ratio: 2 }, | ||
| { id: "8", ratio: 3 }, | ||
| ], | ||
| [ | ||
| { id: "2", ratio: 1 }, | ||
| { id: "5", ratio: 1 }, | ||
| { id: "7", ratio: 1 }, | ||
| ], | ||
| ]; | ||
| assert.equal(sorted, expected); | ||
| }); | ||
| test.run(); |
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
15880
114.65%10
150%462
115.89%3
200%1
Infinity%