From c54a1d40c7ba744e127a0347c6fd6d0478c3bcaf Mon Sep 17 00:00:00 2001 From: Krzysztof kuhy Rudnicki Date: Sun, 4 Oct 2026 22:45:03 +0200 Subject: [PATCH] js_anki: prettier-format card data Co-Authored-By: Claude Opus 5 (1M context) --- python_pkg/js_anki/array.json | 479 ++++++++++++++++++++++++++++++--- python_pkg/js_anki/extras.json | 275 +++++++++++++++++-- 2 files changed, 688 insertions(+), 66 deletions(-) diff --git a/python_pkg/js_anki/array.json b/python_pkg/js_anki/array.json index 84026247..bd31295a 100644 --- a/python_pkg/js_anki/array.json +++ b/python_pkg/js_anki/array.json @@ -1,43 +1,440 @@ [ - {"method":"push","tier":"core","task":"Append x to the END of arr","call":"arr.push(x)","mutates":true,"returns":"the NEW LENGTH (not the array)","example":"const a=[1,2]; const r=a.push(3); return [r,a];","expected":"[3,[1,2,3]]"}, - {"method":"pop","tier":"core","task":"Remove and get the LAST element of arr","call":"arr.pop()","mutates":true,"returns":"the removed element (undefined if empty)","example":"const a=[1,2,3]; const r=a.pop(); return [r,a];","expected":"[3,[1,2]]"}, - {"method":"unshift","tier":"core","task":"Add x to the START of arr","call":"arr.unshift(x)","mutates":true,"returns":"the NEW LENGTH","example":"const a=[2,3]; const r=a.unshift(1); return [r,a];","expected":"[3,[1,2,3]]","gotcha":"O(n): every element shifts. Don't use in hot loops."}, - {"method":"shift","tier":"core","task":"Remove and get the FIRST element of arr","call":"arr.shift()","mutates":true,"returns":"the removed element (undefined if empty)","example":"const a=[1,2,3]; const r=a.shift(); return [r,a];","expected":"[1,[2,3]]","gotcha":"O(n). A BFS queue via shift() is fine on LeetCode sizes, but use an index pointer for big inputs."}, - {"method":"splice","tier":"core","task":"Remove k elements at index i and/or insert items there, in place","call":"arr.splice(i, k, ...items)","mutates":true,"returns":"ARRAY of the removed elements","signature":"arr.splice(start, deleteCount, ...itemsToInsert)","example":"const a=[1,2,3,4]; const r=a.splice(1,2,9); return [r,a];","expected":"[[2,3],[1,9,4]]","gotcha":"Insert only: arr.splice(i, 0, x). Second arg is a COUNT, not an end index."}, - {"method":"slice","tier":"core","task":"Copy arr[i..j) into a new array","call":"arr.slice(i, j)","mutates":false,"returns":"new array (shallow copy); end is exclusive","signature":"arr.slice(start, end) // end exclusive, negatives count from the end, slice() = shallow copy","example":"return [[1,2,3,4].slice(1,3),[1,2,3,4].slice(-2)];","expected":"[[2,3],[3,4]]"}, - {"method":"concat","tier":"core","task":"Join arrays into a new array","call":"a.concat(b, c)","mutates":false,"returns":"new array","example":"return [1].concat([2],[3,4]);","expected":"[1,2,3,4]","gotcha":"[...a, ...b] does the same."}, - {"method":"indexOf","tier":"core","task":"Find the index of x in arr (-1 if absent)","call":"arr.indexOf(x)","mutates":false,"returns":"first index, or -1","example":"return [[1,2,3].indexOf(2),[1,2,3].indexOf(9)];","expected":"[1,-1]","gotcha":"Uses ===, so it can't find NaN; includes() can."}, - {"method":"lastIndexOf","tier":"core","task":"Find the LAST index of x in arr","call":"arr.lastIndexOf(x)","mutates":false,"returns":"last index, or -1","example":"return [1,2,1].lastIndexOf(1);","expected":"2"}, - {"method":"includes","tier":"core","task":"Check whether arr contains x","call":"arr.includes(x)","mutates":false,"returns":"boolean","example":"return [[1,2,3].includes(2),[NaN].includes(NaN)];","expected":"[true,true]"}, - {"method":"find","tier":"core","task":"Get the first element matching a predicate","call":"arr.find((x) => x > 2)","mutates":false,"returns":"the element, or undefined","example":"return [1,2,3,4].find((x)=>x>2);","expected":"3"}, - {"method":"findIndex","tier":"core","task":"Get the INDEX of the first element matching a predicate","call":"arr.findIndex((x) => x > 2)","mutates":false,"returns":"index, or -1","example":"return [1,2,3,4].findIndex((x)=>x>2);","expected":"2"}, - {"method":"findLast","tier":"core","task":"Get the LAST element matching a predicate","call":"arr.findLast((x) => x < 3)","mutates":false,"returns":"the element, or undefined","example":"return [1,2,3,4].findLast((x)=>x<3);","expected":"2"}, - {"method":"filter","tier":"core","task":"Keep only elements matching a predicate","call":"arr.filter((x) => x % 2 === 0)","mutates":false,"returns":"new array","example":"return [1,2,3,4].filter((x)=>x%2===0);","expected":"[2,4]"}, - {"method":"map","tier":"core","task":"Transform every element into a new array","call":"arr.map((x, i) => x * 2)","mutates":false,"returns":"new array of same length","example":"return [1,2,3].map((x)=>x*2);","expected":"[2,4,6]","gotcha":"['1','2','3'].map(parseInt) is [1,NaN,NaN] — map passes the index as the 2nd arg. Use map(Number)."}, - {"method":"reduce","tier":"core","task":"Fold an array into one value (e.g. a sum)","call":"arr.reduce((acc, x) => acc + x, 0)","mutates":false,"returns":"the final accumulator","signature":"arr.reduce((acc, cur, idx, arr) => newAcc, initialValue)","example":"return [1,2,3].reduce((acc,x)=>acc+x,0);","expected":"6","gotcha":"Without an initial value an empty array throws TypeError."}, - {"method":"forEach","tier":"core","task":"Run a side effect for every element","call":"arr.forEach((x, i) => { ... })","mutates":false,"returns":"undefined (not chainable)","example":"const out=[]; [1,2,3].forEach((x)=>out.push(x*2)); return out;","expected":"[2,4,6]","gotcha":"Can't break/return early. Use for...of when you need that."}, - {"method":"some","tier":"core","task":"Check whether ANY element matches","call":"arr.some((x) => x > 2)","mutates":false,"returns":"boolean (short-circuits)","example":"return [[1,2,3].some((x)=>x>2),[].some((x)=>x>2)];","expected":"[true,false]"}, - {"method":"every","tier":"core","task":"Check whether ALL elements match","call":"arr.every((x) => x > 0)","mutates":false,"returns":"boolean (short-circuits)","example":"return [[1,2,3].every((x)=>x>0),[].every((x)=>x>0)];","expected":"[true,true]","gotcha":"Empty array → true."}, - {"method":"sort","tier":"core","task":"Sort numbers ascending (in place)","call":"arr.sort((a, b) => a - b)","mutates":true,"returns":"the SAME array (sorted)","signature":"arr.sort((a, b) => a - b) // ascending; b - a = descending","example":"const a=[10,9,1]; const d=[...a].sort(); a.sort((x,y)=>x-y); return [d,a];","expected":"[[1,10,9],[1,9,10]]","gotcha":"Default sort is LEXICOGRAPHIC: [10,9,1].sort() → [1,10,9]."}, - {"method":"reverse","tier":"core","task":"Reverse an array in place","call":"arr.reverse()","mutates":true,"returns":"the SAME array (reversed)","example":"const a=[1,2,3]; const r=a.reverse(); return [r,a,r===a];","expected":"[[3,2,1],[3,2,1],true]","gotcha":"Need a copy? toReversed() or [...arr].reverse()."}, - {"method":"join","tier":"core","task":"Join array elements into a string","call":"arr.join(sep)","mutates":false,"returns":"string","example":"return [1,2,3].join('-');","expected":"\"1-2-3\"","gotcha":"Default separator is a comma, not empty. Use join('') to concatenate."}, - {"method":"flat","tier":"core","task":"Flatten nested arrays (any depth)","call":"arr.flat(Infinity)","mutates":false,"returns":"new array; default depth is 1","example":"return [1,[2,[3]]].flat(Infinity);","expected":"[1,2,3]"}, - {"method":"flatMap","tier":"core","task":"Map each element to several and flatten one level","call":"arr.flatMap((x) => [x, x * 2])","mutates":false,"returns":"new array","example":"return [1,2].flatMap((x)=>[x,x*2]);","expected":"[1,2,2,4]"}, - {"method":"fill","tier":"core","task":"Create an array of n zeros","call":"new Array(n).fill(0)","mutates":true,"returns":"the SAME array (filled)","signature":"arr.fill(value, start, end)","example":"return new Array(3).fill(0);","expected":"[0,0,0]","gotcha":"fill([]) / fill({}) shares ONE reference across all slots. Use Array.from for a 2D grid."}, - {"method":"Array.from","tier":"core","task":"Create an array of length n from a function of the index","call":"Array.from({ length: n }, (_, i) => i * i)","mutates":false,"returns":"new array","signature":"Array.from(iterableOrArrayLike, mapFn)","example":"return Array.from({length:3},(_,i)=>i*i);","expected":"[0,1,4]","gotcha":"Also converts a Set/Map/string: Array.from(set)."}, - {"method":"Array.from (2D grid)","tier":"core","task":"Create an m×n grid of zeros (rows must be independent)","call":"Array.from({ length: m }, () => Array(n).fill(0))","mutates":false,"returns":"new array of independent rows","example":"const g=Array.from({length:2},()=>Array(3).fill(0)); g[0][0]=1; return g;","expected":"[[1,0,0],[0,0,0]]","gotcha":"Array(m).fill(Array(n).fill(0)) makes every row the SAME array."}, - {"method":"Array.isArray","tier":"core","task":"Check whether a value is an array","call":"Array.isArray(x)","mutates":false,"returns":"boolean","example":"return [Array.isArray([]),Array.isArray('a')];","expected":"[true,false]","gotcha":"typeof [] is 'object', so typeof can't tell."}, - {"method":"at","tier":"core","task":"Get the LAST element (or the nth from the end)","call":"arr.at(-1)","mutates":false,"returns":"element, or undefined","example":"return [[1,2,3].at(-1),[1,2,3].at(0)];","expected":"[3,1]","gotcha":"arr[-1] is undefined — only at() takes negatives."}, - {"method":"entries","tier":"core","task":"Loop with both index and value","call":"for (const [i, x] of arr.entries()) { ... }","mutates":false,"returns":"iterator of [index, value] pairs","example":"return [...['a','b'].entries()];","expected":"[[0,\"a\"],[1,\"b\"]]"}, - {"method":"length","tier":"core","task":"Empty an array in place","call":"arr.length = 0","mutates":true,"returns":"(assignment) — array is truncated","example":"const a=[1,2,3]; a.length=0; return a;","expected":"[]","gotcha":"Aliases see the change; arr = [] only rebinds the variable."}, - {"method":"toSorted","tier":"core","task":"Get a sorted COPY (don't touch the original)","call":"arr.toSorted((a, b) => a - b)","mutates":false,"returns":"new sorted array","example":"const a=[3,1,2]; return [a.toSorted((x,y)=>x-y),a];","expected":"[[1,2,3],[3,1,2]]","gotcha":"ES2023; same lexicographic default as sort()."}, - {"method":"toReversed","tier":"core","task":"Get a reversed COPY (don't touch the original)","call":"arr.toReversed()","mutates":false,"returns":"new reversed array","example":"const a=[1,2,3]; return [a.toReversed(),a];","expected":"[[3,2,1],[1,2,3]]"}, - {"method":"findLastIndex","tier":"rare","task":"Get the INDEX of the last element matching a predicate","call":"arr.findLastIndex((x) => x < 3)","mutates":false,"returns":"index, or -1","example":"return [1,2,3,4].findLastIndex((x)=>x<3);","expected":"1"}, - {"method":"reduceRight","tier":"rare","task":"Fold an array from right to left","call":"arr.reduceRight((acc, x) => acc + x, '')","mutates":false,"returns":"the final accumulator","example":"return ['a','b','c'].reduceRight((acc,x)=>acc+x,'');","expected":"\"cba\""}, - {"method":"copyWithin","tier":"rare","task":"Copy part of the array onto another part of itself, in place","call":"arr.copyWithin(target, start, end)","mutates":true,"returns":"the SAME array","signature":"arr.copyWithin(target, start, end)","example":"return [1,2,3,4,5].copyWithin(0,3);","expected":"[4,5,3,4,5]"}, - {"method":"keys","tier":"rare","task":"Iterate over the indices of an array","call":"arr.keys()","mutates":false,"returns":"iterator of indices","example":"return [...['a','b','c'].keys()];","expected":"[0,1,2]"}, - {"method":"values","tier":"rare","task":"Iterate over the values of an array as an iterator","call":"arr.values()","mutates":false,"returns":"iterator of values","example":"return [...['a','b'].values()];","expected":"[\"a\",\"b\"]"}, - {"method":"toSpliced","tier":"rare","task":"Get a COPY with items removed/inserted (splice without mutation)","call":"arr.toSpliced(i, k, ...items)","mutates":false,"returns":"new array","signature":"arr.toSpliced(start, deleteCount, ...items)","example":"const a=[1,2,3,4]; return [a.toSpliced(1,2,9),a];","expected":"[[1,9,4],[1,2,3,4]]"}, - {"method":"with","tier":"rare","task":"Get a COPY with one index replaced","call":"arr.with(i, v)","mutates":false,"returns":"new array","example":"const a=[1,2,3]; return [a.with(1,9),a];","expected":"[[1,9,3],[1,2,3]]"}, - {"method":"Array.of","tier":"rare","task":"Create an array from the given arguments","call":"Array.of(7)","mutates":false,"returns":"new array","example":"return [Array.of(7),Array(3).length];","expected":"[[7],3]","gotcha":"Array(7) makes 7 empty slots; Array.of(7) makes [7]."} + { + "method": "push", + "tier": "core", + "task": "Append x to the END of arr", + "call": "arr.push(x)", + "mutates": true, + "returns": "the NEW LENGTH (not the array)", + "example": "const a=[1,2]; const r=a.push(3); return [r,a];", + "expected": "[3,[1,2,3]]" + }, + { + "method": "pop", + "tier": "core", + "task": "Remove and get the LAST element of arr", + "call": "arr.pop()", + "mutates": true, + "returns": "the removed element (undefined if empty)", + "example": "const a=[1,2,3]; const r=a.pop(); return [r,a];", + "expected": "[3,[1,2]]" + }, + { + "method": "unshift", + "tier": "core", + "task": "Add x to the START of arr", + "call": "arr.unshift(x)", + "mutates": true, + "returns": "the NEW LENGTH", + "example": "const a=[2,3]; const r=a.unshift(1); return [r,a];", + "expected": "[3,[1,2,3]]", + "gotcha": "O(n): every element shifts. Don't use in hot loops." + }, + { + "method": "shift", + "tier": "core", + "task": "Remove and get the FIRST element of arr", + "call": "arr.shift()", + "mutates": true, + "returns": "the removed element (undefined if empty)", + "example": "const a=[1,2,3]; const r=a.shift(); return [r,a];", + "expected": "[1,[2,3]]", + "gotcha": "O(n). A BFS queue via shift() is fine on LeetCode sizes, but use an index pointer for big inputs." + }, + { + "method": "splice", + "tier": "core", + "task": "Remove k elements at index i and/or insert items there, in place", + "call": "arr.splice(i, k, ...items)", + "mutates": true, + "returns": "ARRAY of the removed elements", + "signature": "arr.splice(start, deleteCount, ...itemsToInsert)", + "example": "const a=[1,2,3,4]; const r=a.splice(1,2,9); return [r,a];", + "expected": "[[2,3],[1,9,4]]", + "gotcha": "Insert only: arr.splice(i, 0, x). Second arg is a COUNT, not an end index." + }, + { + "method": "slice", + "tier": "core", + "task": "Copy arr[i..j) into a new array", + "call": "arr.slice(i, j)", + "mutates": false, + "returns": "new array (shallow copy); end is exclusive", + "signature": "arr.slice(start, end) // end exclusive, negatives count from the end, slice() = shallow copy", + "example": "return [[1,2,3,4].slice(1,3),[1,2,3,4].slice(-2)];", + "expected": "[[2,3],[3,4]]" + }, + { + "method": "concat", + "tier": "core", + "task": "Join arrays into a new array", + "call": "a.concat(b, c)", + "mutates": false, + "returns": "new array", + "example": "return [1].concat([2],[3,4]);", + "expected": "[1,2,3,4]", + "gotcha": "[...a, ...b] does the same." + }, + { + "method": "indexOf", + "tier": "core", + "task": "Find the index of x in arr (-1 if absent)", + "call": "arr.indexOf(x)", + "mutates": false, + "returns": "first index, or -1", + "example": "return [[1,2,3].indexOf(2),[1,2,3].indexOf(9)];", + "expected": "[1,-1]", + "gotcha": "Uses ===, so it can't find NaN; includes() can." + }, + { + "method": "lastIndexOf", + "tier": "core", + "task": "Find the LAST index of x in arr", + "call": "arr.lastIndexOf(x)", + "mutates": false, + "returns": "last index, or -1", + "example": "return [1,2,1].lastIndexOf(1);", + "expected": "2" + }, + { + "method": "includes", + "tier": "core", + "task": "Check whether arr contains x", + "call": "arr.includes(x)", + "mutates": false, + "returns": "boolean", + "example": "return [[1,2,3].includes(2),[NaN].includes(NaN)];", + "expected": "[true,true]" + }, + { + "method": "find", + "tier": "core", + "task": "Get the first element matching a predicate", + "call": "arr.find((x) => x > 2)", + "mutates": false, + "returns": "the element, or undefined", + "example": "return [1,2,3,4].find((x)=>x>2);", + "expected": "3" + }, + { + "method": "findIndex", + "tier": "core", + "task": "Get the INDEX of the first element matching a predicate", + "call": "arr.findIndex((x) => x > 2)", + "mutates": false, + "returns": "index, or -1", + "example": "return [1,2,3,4].findIndex((x)=>x>2);", + "expected": "2" + }, + { + "method": "findLast", + "tier": "core", + "task": "Get the LAST element matching a predicate", + "call": "arr.findLast((x) => x < 3)", + "mutates": false, + "returns": "the element, or undefined", + "example": "return [1,2,3,4].findLast((x)=>x<3);", + "expected": "2" + }, + { + "method": "filter", + "tier": "core", + "task": "Keep only elements matching a predicate", + "call": "arr.filter((x) => x % 2 === 0)", + "mutates": false, + "returns": "new array", + "example": "return [1,2,3,4].filter((x)=>x%2===0);", + "expected": "[2,4]" + }, + { + "method": "map", + "tier": "core", + "task": "Transform every element into a new array", + "call": "arr.map((x, i) => x * 2)", + "mutates": false, + "returns": "new array of same length", + "example": "return [1,2,3].map((x)=>x*2);", + "expected": "[2,4,6]", + "gotcha": "['1','2','3'].map(parseInt) is [1,NaN,NaN] — map passes the index as the 2nd arg. Use map(Number)." + }, + { + "method": "reduce", + "tier": "core", + "task": "Fold an array into one value (e.g. a sum)", + "call": "arr.reduce((acc, x) => acc + x, 0)", + "mutates": false, + "returns": "the final accumulator", + "signature": "arr.reduce((acc, cur, idx, arr) => newAcc, initialValue)", + "example": "return [1,2,3].reduce((acc,x)=>acc+x,0);", + "expected": "6", + "gotcha": "Without an initial value an empty array throws TypeError." + }, + { + "method": "forEach", + "tier": "core", + "task": "Run a side effect for every element", + "call": "arr.forEach((x, i) => { ... })", + "mutates": false, + "returns": "undefined (not chainable)", + "example": "const out=[]; [1,2,3].forEach((x)=>out.push(x*2)); return out;", + "expected": "[2,4,6]", + "gotcha": "Can't break/return early. Use for...of when you need that." + }, + { + "method": "some", + "tier": "core", + "task": "Check whether ANY element matches", + "call": "arr.some((x) => x > 2)", + "mutates": false, + "returns": "boolean (short-circuits)", + "example": "return [[1,2,3].some((x)=>x>2),[].some((x)=>x>2)];", + "expected": "[true,false]" + }, + { + "method": "every", + "tier": "core", + "task": "Check whether ALL elements match", + "call": "arr.every((x) => x > 0)", + "mutates": false, + "returns": "boolean (short-circuits)", + "example": "return [[1,2,3].every((x)=>x>0),[].every((x)=>x>0)];", + "expected": "[true,true]", + "gotcha": "Empty array → true." + }, + { + "method": "sort", + "tier": "core", + "task": "Sort numbers ascending (in place)", + "call": "arr.sort((a, b) => a - b)", + "mutates": true, + "returns": "the SAME array (sorted)", + "signature": "arr.sort((a, b) => a - b) // ascending; b - a = descending", + "example": "const a=[10,9,1]; const d=[...a].sort(); a.sort((x,y)=>x-y); return [d,a];", + "expected": "[[1,10,9],[1,9,10]]", + "gotcha": "Default sort is LEXICOGRAPHIC: [10,9,1].sort() → [1,10,9]." + }, + { + "method": "reverse", + "tier": "core", + "task": "Reverse an array in place", + "call": "arr.reverse()", + "mutates": true, + "returns": "the SAME array (reversed)", + "example": "const a=[1,2,3]; const r=a.reverse(); return [r,a,r===a];", + "expected": "[[3,2,1],[3,2,1],true]", + "gotcha": "Need a copy? toReversed() or [...arr].reverse()." + }, + { + "method": "join", + "tier": "core", + "task": "Join array elements into a string", + "call": "arr.join(sep)", + "mutates": false, + "returns": "string", + "example": "return [1,2,3].join('-');", + "expected": "\"1-2-3\"", + "gotcha": "Default separator is a comma, not empty. Use join('') to concatenate." + }, + { + "method": "flat", + "tier": "core", + "task": "Flatten nested arrays (any depth)", + "call": "arr.flat(Infinity)", + "mutates": false, + "returns": "new array; default depth is 1", + "example": "return [1,[2,[3]]].flat(Infinity);", + "expected": "[1,2,3]" + }, + { + "method": "flatMap", + "tier": "core", + "task": "Map each element to several and flatten one level", + "call": "arr.flatMap((x) => [x, x * 2])", + "mutates": false, + "returns": "new array", + "example": "return [1,2].flatMap((x)=>[x,x*2]);", + "expected": "[1,2,2,4]" + }, + { + "method": "fill", + "tier": "core", + "task": "Create an array of n zeros", + "call": "new Array(n).fill(0)", + "mutates": true, + "returns": "the SAME array (filled)", + "signature": "arr.fill(value, start, end)", + "example": "return new Array(3).fill(0);", + "expected": "[0,0,0]", + "gotcha": "fill([]) / fill({}) shares ONE reference across all slots. Use Array.from for a 2D grid." + }, + { + "method": "Array.from", + "tier": "core", + "task": "Create an array of length n from a function of the index", + "call": "Array.from({ length: n }, (_, i) => i * i)", + "mutates": false, + "returns": "new array", + "signature": "Array.from(iterableOrArrayLike, mapFn)", + "example": "return Array.from({length:3},(_,i)=>i*i);", + "expected": "[0,1,4]", + "gotcha": "Also converts a Set/Map/string: Array.from(set)." + }, + { + "method": "Array.from (2D grid)", + "tier": "core", + "task": "Create an m×n grid of zeros (rows must be independent)", + "call": "Array.from({ length: m }, () => Array(n).fill(0))", + "mutates": false, + "returns": "new array of independent rows", + "example": "const g=Array.from({length:2},()=>Array(3).fill(0)); g[0][0]=1; return g;", + "expected": "[[1,0,0],[0,0,0]]", + "gotcha": "Array(m).fill(Array(n).fill(0)) makes every row the SAME array." + }, + { + "method": "Array.isArray", + "tier": "core", + "task": "Check whether a value is an array", + "call": "Array.isArray(x)", + "mutates": false, + "returns": "boolean", + "example": "return [Array.isArray([]),Array.isArray('a')];", + "expected": "[true,false]", + "gotcha": "typeof [] is 'object', so typeof can't tell." + }, + { + "method": "at", + "tier": "core", + "task": "Get the LAST element (or the nth from the end)", + "call": "arr.at(-1)", + "mutates": false, + "returns": "element, or undefined", + "example": "return [[1,2,3].at(-1),[1,2,3].at(0)];", + "expected": "[3,1]", + "gotcha": "arr[-1] is undefined — only at() takes negatives." + }, + { + "method": "entries", + "tier": "core", + "task": "Loop with both index and value", + "call": "for (const [i, x] of arr.entries()) { ... }", + "mutates": false, + "returns": "iterator of [index, value] pairs", + "example": "return [...['a','b'].entries()];", + "expected": "[[0,\"a\"],[1,\"b\"]]" + }, + { + "method": "length", + "tier": "core", + "task": "Empty an array in place", + "call": "arr.length = 0", + "mutates": true, + "returns": "(assignment) — array is truncated", + "example": "const a=[1,2,3]; a.length=0; return a;", + "expected": "[]", + "gotcha": "Aliases see the change; arr = [] only rebinds the variable." + }, + { + "method": "toSorted", + "tier": "core", + "task": "Get a sorted COPY (don't touch the original)", + "call": "arr.toSorted((a, b) => a - b)", + "mutates": false, + "returns": "new sorted array", + "example": "const a=[3,1,2]; return [a.toSorted((x,y)=>x-y),a];", + "expected": "[[1,2,3],[3,1,2]]", + "gotcha": "ES2023; same lexicographic default as sort()." + }, + { + "method": "toReversed", + "tier": "core", + "task": "Get a reversed COPY (don't touch the original)", + "call": "arr.toReversed()", + "mutates": false, + "returns": "new reversed array", + "example": "const a=[1,2,3]; return [a.toReversed(),a];", + "expected": "[[3,2,1],[1,2,3]]" + }, + { + "method": "findLastIndex", + "tier": "rare", + "task": "Get the INDEX of the last element matching a predicate", + "call": "arr.findLastIndex((x) => x < 3)", + "mutates": false, + "returns": "index, or -1", + "example": "return [1,2,3,4].findLastIndex((x)=>x<3);", + "expected": "1" + }, + { + "method": "reduceRight", + "tier": "rare", + "task": "Fold an array from right to left", + "call": "arr.reduceRight((acc, x) => acc + x, '')", + "mutates": false, + "returns": "the final accumulator", + "example": "return ['a','b','c'].reduceRight((acc,x)=>acc+x,'');", + "expected": "\"cba\"" + }, + { + "method": "copyWithin", + "tier": "rare", + "task": "Copy part of the array onto another part of itself, in place", + "call": "arr.copyWithin(target, start, end)", + "mutates": true, + "returns": "the SAME array", + "signature": "arr.copyWithin(target, start, end)", + "example": "return [1,2,3,4,5].copyWithin(0,3);", + "expected": "[4,5,3,4,5]" + }, + { + "method": "keys", + "tier": "rare", + "task": "Iterate over the indices of an array", + "call": "arr.keys()", + "mutates": false, + "returns": "iterator of indices", + "example": "return [...['a','b','c'].keys()];", + "expected": "[0,1,2]" + }, + { + "method": "values", + "tier": "rare", + "task": "Iterate over the values of an array as an iterator", + "call": "arr.values()", + "mutates": false, + "returns": "iterator of values", + "example": "return [...['a','b'].values()];", + "expected": "[\"a\",\"b\"]" + }, + { + "method": "toSpliced", + "tier": "rare", + "task": "Get a COPY with items removed/inserted (splice without mutation)", + "call": "arr.toSpliced(i, k, ...items)", + "mutates": false, + "returns": "new array", + "signature": "arr.toSpliced(start, deleteCount, ...items)", + "example": "const a=[1,2,3,4]; return [a.toSpliced(1,2,9),a];", + "expected": "[[1,9,4],[1,2,3,4]]" + }, + { + "method": "with", + "tier": "rare", + "task": "Get a COPY with one index replaced", + "call": "arr.with(i, v)", + "mutates": false, + "returns": "new array", + "example": "const a=[1,2,3]; return [a.with(1,9),a];", + "expected": "[[1,9,3],[1,2,3]]" + }, + { + "method": "Array.of", + "tier": "rare", + "task": "Create an array from the given arguments", + "call": "Array.of(7)", + "mutates": false, + "returns": "new array", + "example": "return [Array.of(7),Array(3).length];", + "expected": "[[7],3]", + "gotcha": "Array(7) makes 7 empty slots; Array.of(7) makes [7]." + } ] diff --git a/python_pkg/js_anki/extras.json b/python_pkg/js_anki/extras.json index 9bcb9b40..1b2cb944 100644 --- a/python_pkg/js_anki/extras.json +++ b/python_pkg/js_anki/extras.json @@ -1,27 +1,252 @@ [ - {"method":"Map get/set/has","tier":"core","task":"Store and read key/value pairs in a Map","call":"m.set(k, v); m.get(k); m.has(k); m.size","mutates":true,"returns":"set() returns the Map (chainable); get() returns undefined if missing","example":"const m=new Map(); m.set('a',1); return [m.get('a'),m.get('b'),m.has('a'),m.size];","expected":"[1,null,true,1]","gotcha":"size is a property, not a method. Map keeps insertion order and allows any key type."}, - {"method":"Map delete","tier":"core","task":"Delete a key from a Map","call":"m.delete(k)","mutates":true,"returns":"true if the key existed, else false","example":"const m=new Map([['a',1]]); return [m.delete('a'),m.delete('a'),m.size];","expected":"[true,false,0]"}, - {"method":"Map counter","tier":"core","task":"Count frequencies with a Map","call":"m.set(c, (m.get(c) ?? 0) + 1)","mutates":true,"returns":"(idiom)","example":"const m=new Map(); for (const c of 'aab') m.set(c,(m.get(c)??0)+1); return [...m];","expected":"[[\"a\",2],[\"b\",1]]"}, - {"method":"Map iterate","tier":"core","task":"Loop over a Map's key/value pairs","call":"for (const [k, v] of m) { ... } // m.keys(), m.values() too","returns":"iterates [key, value] pairs in insertion order","example":"const out=[]; for (const [k,v] of new Map([['a',1],['b',2]])) out.push(k+v); return out;","expected":"[\"a1\",\"b2\"]"}, - {"method":"Set basics","tier":"core","task":"Track unique values in a Set","call":"const s = new Set(arr); s.add(x); s.has(x); s.delete(x); s.size","mutates":true,"returns":"add() returns the Set; has()/delete() return boolean","example":"const s=new Set([1,2,2,3]); s.add(4); return [s.size,s.has(2),s.delete(9)];","expected":"[4,true,false]"}, - {"method":"Set dedupe","tier":"core","task":"Remove duplicates from an array","call":"[...new Set(arr)]","mutates":false,"returns":"new array, first-seen order","example":"return [...new Set([3,1,3,2,1])];","expected":"[3,1,2]"}, - {"method":"Object.entries","tier":"core","task":"Get [key, value] pairs of an object","call":"Object.entries(obj) // Object.keys / Object.values","mutates":false,"returns":"array of [key, value]","example":"return Object.entries({a:1,b:2});","expected":"[[\"a\",1],[\"b\",2]]","gotcha":"Integer-like keys come first in ascending order, regardless of insertion."}, - {"method":"Object.fromEntries","tier":"core","task":"Build an object from [key, value] pairs","call":"Object.fromEntries(pairs)","mutates":false,"returns":"new object","example":"return Object.fromEntries([['a',1],['b',2]]);","expected":"{\"a\":1,\"b\":2}","gotcha":"Works with a Map too: Object.fromEntries(map)."}, - {"method":"Object counter","tier":"core","task":"Count frequencies with a plain object","call":"o[c] = (o[c] || 0) + 1","mutates":true,"returns":"(idiom)","example":"const o={}; for (const c of 'aab') o[c]=(o[c]||0)+1; return o;","expected":"{\"a\":2,\"b\":1}","gotcha":"Keys become strings; prefer Map when keys are numbers or you need .size."}, - {"method":"Math.max / Math.min","tier":"core","task":"Max / min of an array","call":"Math.max(...arr)","mutates":false,"returns":"number; Math.max() is -Infinity, Math.min() is Infinity","example":"return [Math.max(...[1,5,3]),Math.min(...[1,5,3])];","expected":"[5,1]","gotcha":"Spread of ~100k+ items overflows the stack; use a loop or reduce."}, - {"method":"Infinity sentinel","tier":"core","task":"Initialize a running min / max","call":"let best = Infinity; // or -Infinity for max","returns":"(idiom)","example":"let best=Infinity; for (const x of [4,2,8]) best=Math.min(best,x); return best;","expected":"2"}, - {"method":"Math.floor / trunc","tier":"core","task":"Integer division (and negatives)","call":"Math.floor(a / b) // Math.trunc rounds toward 0","returns":"number","example":"return [Math.floor(-7/2),Math.trunc(-7/2),Math.floor(7/2)];","expected":"[-4,-3,3]","gotcha":"Floor and trunc differ for negatives. Math.round(-2.5) is -2 (ties go toward +∞)."}, - {"method":"Math.ceil / round / abs / sqrt / pow","tier":"core","task":"Ceil, round, absolute value, square root, power","call":"Math.ceil(x); Math.round(x); Math.abs(x); Math.sqrt(x); x ** n","returns":"number","example":"return [Math.ceil(2.1),Math.round(2.5),Math.abs(-3),Math.sqrt(16),2**10];","expected":"[3,3,3,4,1024]"}, - {"method":"parseInt / Number","tier":"core","task":"Convert a string to a number","call":"parseInt(s, 10) // Number(s) for strict","returns":"number (NaN on failure)","example":"return [parseInt('42px',10),String(Number('42px'))];","expected":"[42,\"NaN\"]","gotcha":"parseInt is lenient (stops at the first bad char); Number is strict. Always pass the radix."}, - {"method":"toString(radix) / parseInt(s, radix)","tier":"core","task":"Convert between decimal and binary (or another base)","call":"n.toString(2); parseInt(s, 2)","returns":"string / number","example":"return [(5).toString(2),parseInt('101',2)];","expected":"[\"101\",5]"}, - {"method":"Bit operations","tier":"core","task":"Shift, mask, XOR, and shift-left bit tricks","call":"n >> 1; n & 1; a ^ b; 1 << k","returns":"32-bit signed integer","example":"return [7>>1,7&1,5^3,1<<3];","expected":"[3,1,6,8]","gotcha":"Bitwise ops work on 32-bit signed ints: above 2^31 use BigInt. >>> 0 gives unsigned."}, - {"method":"Sort numbers asc/desc","tier":"core","task":"Sort numbers ascending and descending","call":"arr.sort((a, b) => a - b) // desc: b - a","returns":"the SAME array, sorted in place","example":"const a=[3,1,2]; return [[...a].sort((x,y)=>x-y),[...a].sort((x,y)=>y-x)];","expected":"[[1,2,3],[3,2,1]]","gotcha":"The comparator returns a number, not a boolean: (a, b) => a > b misbehaves."}, - {"method":"Sort by two keys","tier":"core","task":"Sort pairs by the first value, then by the second","call":"arr.sort((a, b) => a[0] - b[0] || a[1] - b[1])","returns":"the SAME array, sorted in place","example":"return [[2,1],[1,5],[1,2]].sort((a,b)=>a[0]-b[0]||a[1]-b[1]);","expected":"[[1,2],[1,5],[2,1]]","gotcha":"0 is falsy, so || falls through to the next key only on ties."}, - {"method":"Sort strings by length","tier":"core","task":"Sort strings by length","call":"arr.sort((a, b) => a.length - b.length)","returns":"the SAME array, sorted in place","example":"return ['ccc','a','bb'].sort((a,b)=>a.length-b.length);","expected":"[\"a\",\"bb\",\"ccc\"]"}, - {"method":"Swap with destructuring","tier":"core","task":"Swap two variables (or array slots) without a temp","call":"[a, b] = [b, a] // [arr[i], arr[j]] = [arr[j], arr[i]]","returns":"(idiom)","example":"let a=1,b=2; [a,b]=[b,a]; return [a,b];","expected":"[2,1]","gotcha":"The previous line must end with a semicolon or ASI joins them."}, - {"method":"Array destructuring + rest","tier":"core","task":"Split off the first element and keep the rest","call":"const [first, ...rest] = arr","returns":"(idiom)","example":"const [first,...rest]=[1,2,3]; return [first,rest];","expected":"[1,[2,3]]"}, - {"method":"Spread copy","tier":"core","task":"Copy an array / append without mutating","call":"const b = [...a, x]","mutates":false,"returns":"new array (SHALLOW copy)","example":"const a=[1,2]; const b=[...a,3]; return [b,a];","expected":"[[1,2,3],[1,2]]","gotcha":"Nested arrays are still shared. For 2D grids: grid.map((r) => [...r])."}, - {"method":"Object destructuring + rest","tier":"core","task":"Pull one field out of an object and keep the rest","call":"const { a, ...rest } = obj","returns":"(idiom)","example":"const {a,...r}={a:1,b:2,c:3}; return [a,r];","expected":"[1,{\"b\":2,\"c\":3}]"}, - {"method":"structuredClone","tier":"core","task":"Deep-copy a nested array/object","call":"structuredClone(x)","mutates":false,"returns":"deep copy","example":"const a=[[1]]; const b=structuredClone(a); b[0][0]=9; return a;","expected":"[[1]]","gotcha":"Throws on functions. JSON.parse(JSON.stringify(x)) loses undefined/Map/Set."}, - {"method":"?? vs ||","tier":"core","task":"Default a value only when null/undefined (not for 0)","call":"x ?? fallback","returns":"x unless it is null/undefined","example":"return [0||5,0??5];","expected":"[5,0]","gotcha":"|| also replaces 0, '' and false; ?? only replaces null and undefined."} + { + "method": "Map get/set/has", + "tier": "core", + "task": "Store and read key/value pairs in a Map", + "call": "m.set(k, v); m.get(k); m.has(k); m.size", + "mutates": true, + "returns": "set() returns the Map (chainable); get() returns undefined if missing", + "example": "const m=new Map(); m.set('a',1); return [m.get('a'),m.get('b'),m.has('a'),m.size];", + "expected": "[1,null,true,1]", + "gotcha": "size is a property, not a method. Map keeps insertion order and allows any key type." + }, + { + "method": "Map delete", + "tier": "core", + "task": "Delete a key from a Map", + "call": "m.delete(k)", + "mutates": true, + "returns": "true if the key existed, else false", + "example": "const m=new Map([['a',1]]); return [m.delete('a'),m.delete('a'),m.size];", + "expected": "[true,false,0]" + }, + { + "method": "Map counter", + "tier": "core", + "task": "Count frequencies with a Map", + "call": "m.set(c, (m.get(c) ?? 0) + 1)", + "mutates": true, + "returns": "(idiom)", + "example": "const m=new Map(); for (const c of 'aab') m.set(c,(m.get(c)??0)+1); return [...m];", + "expected": "[[\"a\",2],[\"b\",1]]" + }, + { + "method": "Map iterate", + "tier": "core", + "task": "Loop over a Map's key/value pairs", + "call": "for (const [k, v] of m) { ... } // m.keys(), m.values() too", + "returns": "iterates [key, value] pairs in insertion order", + "example": "const out=[]; for (const [k,v] of new Map([['a',1],['b',2]])) out.push(k+v); return out;", + "expected": "[\"a1\",\"b2\"]" + }, + { + "method": "Set basics", + "tier": "core", + "task": "Track unique values in a Set", + "call": "const s = new Set(arr); s.add(x); s.has(x); s.delete(x); s.size", + "mutates": true, + "returns": "add() returns the Set; has()/delete() return boolean", + "example": "const s=new Set([1,2,2,3]); s.add(4); return [s.size,s.has(2),s.delete(9)];", + "expected": "[4,true,false]" + }, + { + "method": "Set dedupe", + "tier": "core", + "task": "Remove duplicates from an array", + "call": "[...new Set(arr)]", + "mutates": false, + "returns": "new array, first-seen order", + "example": "return [...new Set([3,1,3,2,1])];", + "expected": "[3,1,2]" + }, + { + "method": "Object.entries", + "tier": "core", + "task": "Get [key, value] pairs of an object", + "call": "Object.entries(obj) // Object.keys / Object.values", + "mutates": false, + "returns": "array of [key, value]", + "example": "return Object.entries({a:1,b:2});", + "expected": "[[\"a\",1],[\"b\",2]]", + "gotcha": "Integer-like keys come first in ascending order, regardless of insertion." + }, + { + "method": "Object.fromEntries", + "tier": "core", + "task": "Build an object from [key, value] pairs", + "call": "Object.fromEntries(pairs)", + "mutates": false, + "returns": "new object", + "example": "return Object.fromEntries([['a',1],['b',2]]);", + "expected": "{\"a\":1,\"b\":2}", + "gotcha": "Works with a Map too: Object.fromEntries(map)." + }, + { + "method": "Object counter", + "tier": "core", + "task": "Count frequencies with a plain object", + "call": "o[c] = (o[c] || 0) + 1", + "mutates": true, + "returns": "(idiom)", + "example": "const o={}; for (const c of 'aab') o[c]=(o[c]||0)+1; return o;", + "expected": "{\"a\":2,\"b\":1}", + "gotcha": "Keys become strings; prefer Map when keys are numbers or you need .size." + }, + { + "method": "Math.max / Math.min", + "tier": "core", + "task": "Max / min of an array", + "call": "Math.max(...arr)", + "mutates": false, + "returns": "number; Math.max() is -Infinity, Math.min() is Infinity", + "example": "return [Math.max(...[1,5,3]),Math.min(...[1,5,3])];", + "expected": "[5,1]", + "gotcha": "Spread of ~100k+ items overflows the stack; use a loop or reduce." + }, + { + "method": "Infinity sentinel", + "tier": "core", + "task": "Initialize a running min / max", + "call": "let best = Infinity; // or -Infinity for max", + "returns": "(idiom)", + "example": "let best=Infinity; for (const x of [4,2,8]) best=Math.min(best,x); return best;", + "expected": "2" + }, + { + "method": "Math.floor / trunc", + "tier": "core", + "task": "Integer division (and negatives)", + "call": "Math.floor(a / b) // Math.trunc rounds toward 0", + "returns": "number", + "example": "return [Math.floor(-7/2),Math.trunc(-7/2),Math.floor(7/2)];", + "expected": "[-4,-3,3]", + "gotcha": "Floor and trunc differ for negatives. Math.round(-2.5) is -2 (ties go toward +∞)." + }, + { + "method": "Math.ceil / round / abs / sqrt / pow", + "tier": "core", + "task": "Ceil, round, absolute value, square root, power", + "call": "Math.ceil(x); Math.round(x); Math.abs(x); Math.sqrt(x); x ** n", + "returns": "number", + "example": "return [Math.ceil(2.1),Math.round(2.5),Math.abs(-3),Math.sqrt(16),2**10];", + "expected": "[3,3,3,4,1024]" + }, + { + "method": "parseInt / Number", + "tier": "core", + "task": "Convert a string to a number", + "call": "parseInt(s, 10) // Number(s) for strict", + "returns": "number (NaN on failure)", + "example": "return [parseInt('42px',10),String(Number('42px'))];", + "expected": "[42,\"NaN\"]", + "gotcha": "parseInt is lenient (stops at the first bad char); Number is strict. Always pass the radix." + }, + { + "method": "toString(radix) / parseInt(s, radix)", + "tier": "core", + "task": "Convert between decimal and binary (or another base)", + "call": "n.toString(2); parseInt(s, 2)", + "returns": "string / number", + "example": "return [(5).toString(2),parseInt('101',2)];", + "expected": "[\"101\",5]" + }, + { + "method": "Bit operations", + "tier": "core", + "task": "Shift, mask, XOR, and shift-left bit tricks", + "call": "n >> 1; n & 1; a ^ b; 1 << k", + "returns": "32-bit signed integer", + "example": "return [7>>1,7&1,5^3,1<<3];", + "expected": "[3,1,6,8]", + "gotcha": "Bitwise ops work on 32-bit signed ints: above 2^31 use BigInt. >>> 0 gives unsigned." + }, + { + "method": "Sort numbers asc/desc", + "tier": "core", + "task": "Sort numbers ascending and descending", + "call": "arr.sort((a, b) => a - b) // desc: b - a", + "returns": "the SAME array, sorted in place", + "example": "const a=[3,1,2]; return [[...a].sort((x,y)=>x-y),[...a].sort((x,y)=>y-x)];", + "expected": "[[1,2,3],[3,2,1]]", + "gotcha": "The comparator returns a number, not a boolean: (a, b) => a > b misbehaves." + }, + { + "method": "Sort by two keys", + "tier": "core", + "task": "Sort pairs by the first value, then by the second", + "call": "arr.sort((a, b) => a[0] - b[0] || a[1] - b[1])", + "returns": "the SAME array, sorted in place", + "example": "return [[2,1],[1,5],[1,2]].sort((a,b)=>a[0]-b[0]||a[1]-b[1]);", + "expected": "[[1,2],[1,5],[2,1]]", + "gotcha": "0 is falsy, so || falls through to the next key only on ties." + }, + { + "method": "Sort strings by length", + "tier": "core", + "task": "Sort strings by length", + "call": "arr.sort((a, b) => a.length - b.length)", + "returns": "the SAME array, sorted in place", + "example": "return ['ccc','a','bb'].sort((a,b)=>a.length-b.length);", + "expected": "[\"a\",\"bb\",\"ccc\"]" + }, + { + "method": "Swap with destructuring", + "tier": "core", + "task": "Swap two variables (or array slots) without a temp", + "call": "[a, b] = [b, a] // [arr[i], arr[j]] = [arr[j], arr[i]]", + "returns": "(idiom)", + "example": "let a=1,b=2; [a,b]=[b,a]; return [a,b];", + "expected": "[2,1]", + "gotcha": "The previous line must end with a semicolon or ASI joins them." + }, + { + "method": "Array destructuring + rest", + "tier": "core", + "task": "Split off the first element and keep the rest", + "call": "const [first, ...rest] = arr", + "returns": "(idiom)", + "example": "const [first,...rest]=[1,2,3]; return [first,rest];", + "expected": "[1,[2,3]]" + }, + { + "method": "Spread copy", + "tier": "core", + "task": "Copy an array / append without mutating", + "call": "const b = [...a, x]", + "mutates": false, + "returns": "new array (SHALLOW copy)", + "example": "const a=[1,2]; const b=[...a,3]; return [b,a];", + "expected": "[[1,2,3],[1,2]]", + "gotcha": "Nested arrays are still shared. For 2D grids: grid.map((r) => [...r])." + }, + { + "method": "Object destructuring + rest", + "tier": "core", + "task": "Pull one field out of an object and keep the rest", + "call": "const { a, ...rest } = obj", + "returns": "(idiom)", + "example": "const {a,...r}={a:1,b:2,c:3}; return [a,r];", + "expected": "[1,{\"b\":2,\"c\":3}]" + }, + { + "method": "structuredClone", + "tier": "core", + "task": "Deep-copy a nested array/object", + "call": "structuredClone(x)", + "mutates": false, + "returns": "deep copy", + "example": "const a=[[1]]; const b=structuredClone(a); b[0][0]=9; return a;", + "expected": "[[1]]", + "gotcha": "Throws on functions. JSON.parse(JSON.stringify(x)) loses undefined/Map/Set." + }, + { + "method": "?? vs ||", + "tier": "core", + "task": "Default a value only when null/undefined (not for 0)", + "call": "x ?? fallback", + "returns": "x unless it is null/undefined", + "example": "return [0||5,0??5];", + "expected": "[5,0]", + "gotcha": "|| also replaces 0, '' and false; ?? only replaces null and undefined." + } ]