├── logo.png ├── .gitignore ├── Adapter.md └── Array.md /logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ConardLi/30-seconds-of-code-Zh-CN/HEAD/logo.png -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | Thumbs.db 3 | db.json 4 | *.log 5 | node_modules/ 6 | public/ 7 | .deploy*/ -------------------------------------------------------------------------------- /Adapter.md: -------------------------------------------------------------------------------- 1 | [![Logo](/logo.png)](https://github.com/ConardLi/30-seconds-of-code-Zh-CN) 2 | 3 | ## 目录 4 | 5 | * [`ary`](#ary) 6 | * [`call`](#call) 7 | * [`collectInto`](#collectinto) 8 | * [`flip`](#flip) 9 | * [`over`](#over) 10 | * [`overArgs`](#overargs) 11 | * [`pipeAsyncFunctions`](#pipeasyncfunctions) 12 | * [`pipeFunctions`](#pipefunctions) 13 | * [`promisify`](#promisify) 14 | * [`rearg`](#rearg) 15 | * [`spreadOver`](#spreadover) 16 | * [`unary`](#unary) 17 | 18 | 19 | ## 🔌 Adapter 20 | 21 | ### ary 22 | 23 | 创建一个可以接收n个参数的函数, 忽略其他额外的参数。 24 | 25 | 调用提供的函数`fn`,参数最多为n个, 使用 `Array.prototype.slice(0,n)` 和展开操作符 (`...`)。 26 | 27 | ```js 28 | const ary = (fn, n) => (...args) => fn(...args.slice(0, n)); 29 | ``` 30 | 31 | 32 | 示例 33 | 34 | ```js 35 | const firstTwoMax = ary(Math.max, 2); 36 | [[2, 6, 'a'], [8, 4, 6], [10]].map(x => firstTwoMax(...x)); // [6, 8, 10] 37 | ``` 38 | 39 | 40 | 41 | 42 | 43 | ### call 44 | 45 | 给定一个key和一组参数,给定一个上下文时调用它们。主要用于合并。 46 | 47 | 使用闭包调用上下文中key对应的值,即带有存储参数的函数。 48 | 49 | ```js 50 | const call = (key, ...args) => context => context[key](...args); 51 | ``` 52 | 53 | 54 | 示例 55 | 56 | ```js 57 | Promise.resolve([1, 2, 3]) 58 | .then(call('map', x => 2 * x)) 59 | .then(console.log); // [ 2, 4, 6 ] 60 | const map = call.bind(null, 'map'); 61 | Promise.resolve([1, 2, 3]) 62 | .then(map(x => 2 * x)) 63 | .then(console.log); // [ 2, 4, 6 ] 64 | ``` 65 | 66 | 67 | 68 | ### collectInto 69 | 70 | 将一个接收数组参数的函数改变为可变参数的函数。 71 | 72 | 给定一个函数,返回一个闭包,该闭包将所有输入收集到一个数组接受函数中。 73 | 74 | ```js 75 | const collectInto = fn => (...args) => fn(args); 76 | ``` 77 | 78 | 79 | 示例 80 | 81 | ```js 82 | const Pall = collectInto(Promise.all.bind(Promise)); 83 | let p1 = Promise.resolve(1); 84 | let p2 = Promise.resolve(2); 85 | let p3 = new Promise(resolve => setTimeout(resolve, 2000, 3)); 86 | Pall(p1, p2, p3).then(console.log); // [1, 2, 3] (after about 2 seconds) 87 | ``` 88 | 89 | 90 | 91 | 92 | 93 | ### flip 94 | 95 | Flip以一个函数作为参数,然后把第一个参数作为最后一个参数。 96 | 97 | 返回一个可变参数的闭包,在应用其他参数前,先把第一个以外的其他参数作为第一个参数。 98 | 99 | 100 | ```js 101 | const flip = fn => (first, ...rest) => fn(...rest, first); 102 | ``` 103 | 104 | 105 | 示例 106 | 107 | ```js 108 | let a = { name: 'John Smith' }; 109 | let b = {}; 110 | const mergeFrom = flip(Object.assign); 111 | let mergePerson = mergeFrom.bind(null, a); 112 | mergePerson(b); // == b 113 | b = {}; 114 | Object.assign(b, a); // == b 115 | ``` 116 | 117 | 118 | 119 | 120 | 121 | ### over 122 | 123 | 创建一个函数,这个函数可以调用每一个被传入的并且才有参数的函数,然后返回结果。 124 | 125 | 使用 `Array.prototype.map()` 和 `Function.prototype.apply()`将每个函数应用给定的参数。 126 | 127 | ```js 128 | const over = (...fns) => (...args) => fns.map(fn => fn.apply(null, args)); 129 | ``` 130 | 131 | 132 | 示例 133 | 134 | ```js 135 | const minMax = over(Math.min, Math.max); 136 | minMax(1, 2, 3, 4, 5); // [1,5] 137 | ``` 138 | 139 | 140 | 141 | 142 | 143 | ### overArgs 144 | 145 | 创建一个函数,它可以调用提供的被转换参数的函数。 146 | 147 | 使用`Array.prototype.map()`将`transforms`应用于`args`,并结合扩展运算符(`…`)将转换后的参数传递给`fn`。 148 | 149 | ```js 150 | const overArgs = (fn, transforms) => (...args) => fn(...args.map((val, i) => transforms[i](val))); 151 | ``` 152 | 153 | 154 | 示例 155 | 156 | ```js 157 | const square = n => n * n; 158 | const double = n => n * 2; 159 | const fn = overArgs((x, y) => [x, y], [square, double]); 160 | fn(9, 3); // [81, 6] 161 | ``` 162 | 163 | 164 | 165 | 166 | 167 | ### pipeAsyncFunctions 168 | 169 | 为异步函数执行从左到右的函数组合。 170 | 171 | 在扩展操作符(`…`)中使用`Array.prototype.reduce() `来使用`Promise.then()`执行从左到右的函数组合。 172 | 这些函数可以返回简单值、`Promise`的组合,也可以定义为通过`await`返回的`async`值。 173 | 所有函数必须是一元的。 174 | ```js 175 | const pipeAsyncFunctions = (...fns) => arg => fns.reduce((p, f) => p.then(f), Promise.resolve(arg)); 176 | ``` 177 | 178 | > arr.reduce(callback[, initialValue]) 179 | 180 | ``` 181 | callback 182 | 执行数组中每个值的函数,包含四个参数: 183 | accumulator 184 | 累计器累计回调的返回值; 它是上一次调用回调时返回的累积值,或initialValue(见于下方)。 185 | currentValue 186 | 数组中正在处理的元素。 187 | currentIndex可选 188 | 数组中正在处理的当前元素的索引。 如果提供了initialValue,则起始索引号为0,否则为1。 189 | array可选 190 | 调用reduce()的数组 191 | initialValue可选 192 | 作为第一次调用 callback函数时的第一个参数的值。 如果没有提供初始值,则将使用数组中的第一个元素。 在没有初始值的空数组上调用 reduce 将报错。 193 | ``` 194 | 195 | 196 | 示例 197 | 198 | ```js 199 | 200 | const sum = pipeAsyncFunctions( 201 | x => x + 1, 202 | x => new Promise(resolve => setTimeout(() => resolve(x + 2), 1000)), 203 | x => x + 3, 204 | async x => (await x) + 4 205 | ); 206 | (async() => { 207 | console.log(await sum(5)); // 15 (after one second) 208 | })(); 209 | ``` 210 | 211 | 212 | ### pipeFunctions 213 | 214 | 执行从左到右的函数组合。 215 | 216 | 在展开操作符(`…`)中使用`Array.prototype.reduce()`来执行从左到右的函数组合。 217 | 第一个(最左边的)函数可以接受一个或多个参数; 其余的函数必须是一元的。 218 | 219 | ```js 220 | const pipeFunctions = (...fns) => fns.reduce((f, g) => (...args) => g(f(...args))); 221 | ``` 222 | 223 | 224 | 示例 225 | 226 | ```js 227 | const add5 = x => x + 5; 228 | const multiply = (x, y) => x * y; 229 | const multiplyAndAdd5 = pipeFunctions(multiply, add5); 230 | multiplyAndAdd5(5, 2); // 15 231 | ``` 232 | 233 | 234 | ### promisify 235 | 236 | 把一个异步函数转换成返回promise的。 237 | 238 | 使用局部套用返回一个函数,该函数返回一个调用原始函数的`Promise`。 239 | 使用的`...`操作符来传入所有参数。 240 | 241 | 242 | ```js 243 | const promisify = func => (...args) => 244 | new Promise((resolve, reject) => 245 | func(...args, (err, result) => (err ? reject(err) : resolve(result))) 246 | ); 247 | ``` 248 | 249 | 250 | 示例 251 | 252 | ```js 253 | const delay = promisify((d, cb) => setTimeout(cb, d)); 254 | delay(2000).then(() => console.log('Hi!')); // Promise resolves after 2s 255 | ``` 256 | 257 | 258 | 259 | 260 | 261 | ### rearg 262 | 263 | 264 | 创建一个调用提供的函数的函数,该函数的参数按照指定的索引排列。 265 | 266 | 利用 `Array.prototype.map()` 根据 `indexes` 和展开操作符 (`...`) 对参数进行重新排序,将转换后的参数传递给 `fn`. 267 | 268 | ```js 269 | const rearg = (fn, indexes) => (...args) => fn(...indexes.map(i => args[i])); 270 | ``` 271 | 272 | 273 | 示例 274 | 275 | ```js 276 | var rearged = rearg( 277 | function(a, b, c) { 278 | return [a, b, c]; 279 | }, 280 | [2, 0, 1] 281 | ); 282 | rearged('b', 'c', 'a'); // ['a', 'b', 'c'] 283 | ``` 284 | 285 | 286 | 287 | ### spreadOver 288 | 289 | 接受一个可变参数函数并返回一个闭包,该闭包接受一个参数数组以映射到函数的输入。 290 | 291 | 使用闭包和扩展操作符(`…`)将参数数组映射到函数的输入。 292 | 293 | ```js 294 | const spreadOver = fn => argsArr => fn(...argsArr); 295 | ``` 296 | 297 | 298 | 示例 299 | 300 | ```js 301 | const arrayMax = spreadOver(Math.max); 302 | arrayMax([1, 2, 3]); // 3 303 | ``` 304 | 305 | ### unary 306 | 307 | 创建一个最多接受一个参数的函数,忽略任何其他参数。 308 | 309 | 只把第一个参数传递给要调用的函数`fn`。 310 | 311 | ```js 312 | const unary = fn => val => fn(val); 313 | ``` 314 | 315 | 示例 316 | 317 | ```js 318 | ['6', '8', '10'].map(unary(parseInt)); // [6, 8, 10] 319 | ``` 320 | 321 | --- 322 | -------------------------------------------------------------------------------- /Array.md: -------------------------------------------------------------------------------- 1 | [![Logo](/logo.png)](https://github.com/ConardLi/30-seconds-of-code-Zh-CN) 2 | 3 | ## 目录 4 | 5 | 6 | * [`all`](#all) 7 | * [`allEqual`](#allequal) 8 | * [`any`](#any) 9 | * [`arrayToCSV`](#arraytocsv) 10 | * [`bifurcate`](#bifurcate) 11 | * [`bifurcateBy`](#bifurcateby) 12 | * [`chunk`](#chunk) 13 | * [`compact`](#compact) 14 | * [`countBy`](#countby) 15 | * [`countOccurrences`](#countoccurrences) 16 | * [`deepFlatten`](#deepflatten) 17 | * [`difference`](#difference) 18 | * [`differenceBy`](#differenceby) 19 | * [`differenceWith`](#differencewith) 20 | * [`drop`](#drop) 21 | * [`dropRight`](#dropright) 22 | * [`dropRightWhile`](#droprightwhile) 23 | * [`dropWhile`](#dropwhile) 24 | * [`everyNth`](#everynth) 25 | * [`filterFalsy`](#filterfalsy) 26 | * [`filterNonUnique`](#filternonunique) 27 | * [`filterNonUniqueBy`](#filternonuniqueby) 28 | * [`findLast`](#findlast) 29 | * [`findLastIndex`](#findlastindex) 30 | * [`flatten`](#flatten) 31 | * [`forEachRight`](#foreachright) 32 | * [`groupBy`](#groupby) 33 | * [`head`](#head) 34 | * [`indexOfAll`](#indexofall) 35 | * [`initial`](#initial) 36 | * [`initialize2DArray`](#initialize2darray) 37 | * [`initializeArrayWithRange`](#initializearraywithrange) 38 | * [`initializeArrayWithRangeRight`](#initializearraywithrangeright) 39 | * [`initializeArrayWithValues`](#initializearraywithvalues) 40 | * [`initializeNDArray`](#initializendarray) 41 | * [`intersection`](#intersection) 42 | * [`intersectionBy`](#intersectionby) 43 | * [`intersectionWith`](#intersectionwith) 44 | * [`isSorted`](#issorted) 45 | * [`join`](#join) 46 | * [`JSONtoCSV`](#jsontocsv-) 47 | * [`last`](#last) 48 | * [`longestItem`](#longestitem) 49 | * [`mapObject`](#mapobject-) 50 | * [`maxN`](#maxn) 51 | * [`minN`](#minn) 52 | * [`none`](#none) 53 | * [`nthElement`](#nthelement) 54 | * [`offset`](#offset) 55 | * [`partition`](#partition) 56 | * [`permutations`](#permutations-) 57 | * [`pull`](#pull) 58 | * [`pullAtIndex`](#pullatindex-) 59 | * [`pullAtValue`](#pullatvalue-) 60 | * [`pullBy`](#pullby-) 61 | * [`reducedFilter`](#reducedfilter) 62 | * [`reduceSuccessive`](#reducesuccessive) 63 | * [`reduceWhich`](#reducewhich) 64 | * [`reject`](#reject) 65 | * [`remove`](#remove) 66 | * [`sample`](#sample) 67 | * [`sampleSize`](#samplesize) 68 | * [`shank`](#shank) 69 | * [`shuffle`](#shuffle) 70 | * [`similarity`](#similarity) 71 | * [`sortedIndex`](#sortedindex) 72 | * [`sortedIndexBy`](#sortedindexby) 73 | * [`sortedLastIndex`](#sortedlastindex) 74 | * [`sortedLastIndexBy`](#sortedlastindexby) 75 | * [`stableSort`](#stablesort-) 76 | * [`symmetricDifference`](#symmetricdifference) 77 | * [`symmetricDifferenceBy`](#symmetricdifferenceby) 78 | * [`symmetricDifferenceWith`](#symmetricdifferencewith) 79 | * [`tail`](#tail) 80 | * [`take`](#take) 81 | * [`takeRight`](#takeright) 82 | * [`takeRightWhile`](#takerightwhile) 83 | * [`takeWhile`](#takewhile) 84 | * [`toHash`](#tohash) 85 | * [`union`](#union) 86 | * [`unionBy`](#unionby) 87 | * [`unionWith`](#unionwith) 88 | * [`uniqueElements`](#uniqueelements) 89 | * [`uniqueElementsBy`](#uniqueelementsby) 90 | * [`uniqueElementsByRight`](#uniqueelementsbyright) 91 | * [`uniqueSymmetricDifference`](#uniquesymmetricdifference) 92 | * [`unzip`](#unzip) 93 | * [`unzipWith`](#unzipwith-) 94 | * [`without`](#without) 95 | * [`xProd`](#xprod) 96 | * [`zip`](#zip) 97 | * [`zipObject`](#zipobject) 98 | * [`zipWith`](#zipwith-) 99 | 100 | 101 | 102 | ## 📚 Array 103 | 104 | ### all 105 | 106 | 如果被提供的断言函数接收数组中每个元素作为参数都返回`true`,则返回`true`,否则返回`false`。 107 | 108 | 109 | 使用 `Array.prototype.every()`来测试是否第二个参数`fn`以集合中每个元素作为参数都返回`true`,使用`Boolean`作为默认值。 110 | 111 | ```js 112 | const all = (arr, fn = Boolean) => arr.every(fn); 113 | ``` 114 | 115 | 示例 116 | 117 | ```js 118 | all([4, 2, 3], x => x > 1); // true 119 | all([1, 2, 3]); // true 120 | ``` 121 | 122 | 123 | ### allEqual 124 | 125 | 检查是否数组中所有的元素都是相等的。 126 | 127 | 使用 `Array.prototype.every()` 来检测是否数组中的所有元素都和第一个元素相等。 128 | 129 | ```js 130 | const allEqual = arr => arr.every(val => val === arr[0]); 131 | ``` 132 | 133 | 134 | 示例 135 | 136 | ```js 137 | allEqual([1, 2, 3, 4, 5, 6]); // false 138 | allEqual([1, 1, 1, 1]); // true 139 | ``` 140 | 141 | 142 | ### any 143 | 144 | 如果被提供的断言函数接收数组中任意一个元素作为参数都返回`true`,则返回`true`,否则返回`false`。 145 | 146 | 使用 `Array.prototype.every()`来测试是否第二个参数`fn`以集合中任意一个元素作为参数都返回`true`,使用`Boolean`作为默认值。 147 | 148 | 149 | ```js 150 | const any = (arr, fn = Boolean) => arr.some(fn); 151 | ``` 152 | 153 | 154 | 示例 155 | 156 | ```js 157 | any([0, 1, 2, 0], x => x >= 2); // true 158 | any([0, 0, 1, 0]); // true 159 | ``` 160 | 161 | 162 | ### arrayToCSV 163 | 164 | 将2D数组转换为逗号分隔值(CSV)字符串。 165 | 166 | 使用 `Array.prototype.map()` 和 `Array.prototype.join(delimiter)` 将一个一维数组转换为字符串。 167 | 168 | 使用 `Array.prototype.join('\n')` 将所有行合并成CSV字符串, 用换行符分割每一行。 169 | 170 | 如果没有第二哥参数, `delimiter`会使用一个默认分隔符 `,`. 171 | 172 | ```js 173 | const arrayToCSV = (arr, delimiter = ',') => 174 | arr.map(v => v.map(x => `"${x}"`).join(delimiter)).join('\n'); 175 | ``` 176 | 177 | 178 | 示例 179 | 180 | ```js 181 | arrayToCSV([['a', 'b'], ['c', 'd']]); // '"a","b"\n"c","d"' 182 | arrayToCSV([['a', 'b'], ['c', 'd']], ';'); // '"a";"b"\n"c";"d"' 183 | ``` 184 | 185 | 186 | ### bifurcate 187 | 188 | 将数据分为两组,如果元素在 `filter`数组中对应的是`true`,集合中相应的元素应加入第一个数组,否则加入第二个数组。 189 | 190 | 基于`filter`使用`Array.prototype.reduce()` 和 `Array.prototype.push()`将元素分组。 191 | 192 | ```js 193 | const bifurcate = (arr, filter) => 194 | arr.reduce((acc, val, i) => (acc[filter[i] ? 0 : 1].push(val), acc), [[], []]); 195 | ``` 196 | 197 | 198 | 示例 199 | 200 | ```js 201 | bifurcate(['beep', 'boop', 'foo', 'bar'], [true, true, false, true]); // [ ['beep', 'boop', 'bar'], ['foo'] ] 202 | ``` 203 | 204 | ### bifurcateBy 205 | 206 | 根据断言函数将数据分成两组,断言函数将指定集合中的元素属于哪个组。如果断言函数返回`true`,元素加入第一个数组,否则加入第二个数组。 207 | 208 | 给予`fn`接收元素的返回值,使用`Array.prototype.reduce()` 和 `Array.prototype.push()`将元素分组。 209 | ```js 210 | const bifurcateBy = (arr, fn) => 211 | arr.reduce((acc, val, i) => (acc[fn(val, i) ? 0 : 1].push(val), acc), [[], []]); 212 | ``` 213 | 214 | 215 | 示例 216 | 217 | ```js 218 | bifurcateBy(['beep', 'boop', 'foo', 'bar'], x => x[0] === 'b'); // [ ['beep', 'boop', 'bar'], ['foo'] ] 219 | ``` 220 | 221 | 222 | ### chunk 223 | 224 | 将数组分成指定大小的较小数组。 225 | 226 | 使用 `Array.from()`创建一个新的数组,该数组与将要生成的块的数量相匹配。 227 | 使用 `Array.prototype.slice()` 将新数组的每个元素映射到长度为`size`的块。 228 | 如果原始的数组不能被均匀的分割,最后的一块将包含剩余的元素。 229 | 230 | ```js 231 | const chunk = (arr, size) => 232 | Array.from({ length: Math.ceil(arr.length / size) }, (v, i) => 233 | arr.slice(i * size, i * size + size) 234 | ); 235 | ``` 236 | 237 | 238 | 示例 239 | 240 | ```js 241 | chunk([1, 2, 3, 4, 5], 2); // [[1,2],[3,4],[5]] 242 | ``` 243 | 244 | 245 | ### compact 246 | 247 | 删除数组中错误的元素 248 | 249 | 使用 `Array.prototype.filter()` 过滤掉错误的元素 (`false`, `null`, `0`, `""`, `undefined`, `NaN`). 250 | 251 | ```js 252 | const compact = arr => arr.filter(Boolean); 253 | ``` 254 | 255 | 示例 256 | 257 | ```js 258 | compact([0, 1, false, 2, '', 3, 'a', 'e' * 23, NaN, 's', 34]); // [ 1, 2, 3, 'a', 's', 34 ] 259 | ``` 260 | 261 | ### countBy 262 | 263 | 基于给定的函数将数组中的元素进行分组,并返回每个组中的元素数。 264 | 265 | 使用`Array.prototype.map()`来将数组中的每个元素映射到函数或属性名。 266 | 使用 `Array.prototype.reduce()` 创建一个对象,其中的键是从映射结果生成的。 267 | 268 | ```js 269 | const countBy = (arr, fn) => 270 | arr.map(typeof fn === 'function' ? fn : val => val[fn]).reduce((acc, val) => { 271 | acc[val] = (acc[val] || 0) + 1; 272 | return acc; 273 | }, {}); 274 | ``` 275 | 276 | 277 | 示例 278 | 279 | ```js 280 | countBy([6.1, 4.2, 6.3], Math.floor); // {4: 1, 6: 2} 281 | countBy(['one', 'two', 'three'], 'length'); // {3: 2, 5: 1} 282 | ``` 283 | 284 | 285 | ### countOccurrences 286 | 287 | 计算数组中某个元素出现的次数。 288 | 289 | Use `Array.prototype.reduce()`在每次遇到数组中的特定值时递增计数器。 290 | 291 | ```js 292 | const countOccurrences = (arr, val) => arr.reduce((a, v) => (v === val ? a + 1 : a), 0); 293 | ``` 294 | 295 | 示例 296 | 297 | ```js 298 | countOccurrences([1, 1, 2, 1, 2, 3], 1); // 3 299 | ``` 300 | 301 | 302 | ### deepFlatten 303 | 304 | 将一个多层嵌套的数组转转换成一个一元数组。 305 | 306 | 使用递归. 307 | Use `Array.prototype.concat()` with an empty array (`[]`) and the spread operator (`...`) to flatten an array. 308 | 使用 `Array.prototype.concat()` 和一个空数组(`[]`)以及展开运算符(`...`)来平铺一个数组。 309 | 当每个元素还是一个数字时,递归铺平他。 310 | 311 | ```js 312 | const deepFlatten = arr => [].concat(...arr.map(v => (Array.isArray(v) ? deepFlatten(v) : v))); 313 | ``` 314 | 315 | 316 | 示例 317 | 318 | ```js 319 | deepFlatten([1, [2], [[3], 4], 5]); // [1,2,3,4,5] 320 | ``` 321 | 322 | ### difference 323 | 324 | 返回两个数组间的差异值。 325 | 326 | 从数组`b`中创建一个 `Set` ,然后用使用另一个数组`a`的`Array.prototype.filter()` 方法过滤掉`b`中的元素。 327 | 328 | ```js 329 | const difference = (a, b) => { 330 | const s = new Set(b); 331 | return a.filter(x => !s.has(x)); 332 | }; 333 | ``` 334 | 335 | 示例 336 | 337 | ```js 338 | difference([1, 2, 3], [1, 2, 4]); // [3] 339 | ``` 340 | 341 | 342 | ### differenceBy 343 | 344 | 将提供的函数应用于两个数组的每个数组元素后,返回两个数组中不同的元素。 345 | 346 | 通过`b`中的每个元素调用 `fn`后创建一个 `Set` ,然后将`Array.prototype.filter()` 与`fn`调用后的`a`结合使用,只保留先前创建的集合中不包含的值。 347 | 348 | ```js 349 | const differenceBy = (a, b, fn) => { 350 | const s = new Set(b.map(fn)); 351 | return a.filter(x => !s.has(fn(x))); 352 | }; 353 | ``` 354 | 355 | 示例 356 | 357 | ```js 358 | differenceBy([2.1, 1.2], [2.3, 3.4], Math.floor); // [1.2] 359 | differenceBy([{ x: 2 }, { x: 1 }], [{ x: 1 }], v => v.x); // [ { x: 2 } ] 360 | ``` 361 | 362 | 363 | ### differenceWith 364 | 365 | 366 | 筛选出比较器函数不返回`true`的数组中的所有值。 367 | 368 | 使用 `Array.prototype.filter()` 和 `Array.prototype.findIndex()` 查找合适的值。 369 | 370 | ```js 371 | const differenceWith = (arr, val, comp) => arr.filter(a => val.findIndex(b => comp(a, b)) === -1); 372 | ``` 373 | 374 | 375 | 示例 376 | 377 | ```js 378 | differenceWith([1, 1.2, 1.5, 3, 0], [1.9, 3, 0], (a, b) => Math.round(a) === Math.round(b)); // [1, 1.2] 379 | ``` 380 | 381 | ### drop 382 | 383 | 返回一个新数组,从原数组左边删除`n`个元素。 384 | 385 | 使用 `Array.prototype.slice()` 从左侧删除指定数量的元素。 386 | 387 | ```js 388 | const drop = (arr, n = 1) => arr.slice(n); 389 | ``` 390 | 391 | > slice(n) 表示取数组下标n以后的元素(含n) 392 | 393 | 示例 394 | 395 | ```js 396 | drop([1, 2, 3]); // [2,3] 397 | drop([1, 2, 3], 2); // [3] 398 | drop([1, 2, 3], 42); // [] 399 | ``` 400 | 401 | 402 | ### dropRight 403 | 404 | 返回一个新数组,从原数组右边删除`n`个元素。 405 | 406 | 使用 `Array.prototype.slice()`从右边删除指定数目的元素。 407 | 408 | ```js 409 | const dropRight = (arr, n = 1) => arr.slice(0, -n); 410 | ``` 411 | 412 | > slice(0, -n) 表示取数组第一个到倒数第n个元素(不含-n) 413 | 414 | 415 | 示例 416 | 417 | ```js 418 | dropRight([1, 2, 3]); // [1,2] 419 | dropRight([1, 2, 3], 2); // [1] 420 | dropRight([1, 2, 3], 42); // [] 421 | ``` 422 | 423 | 424 | ### dropRightWhile 425 | 426 | 从数组尾部移除数组中的元素,直到传递的函数返回`true`。返回数组中剩余的元素。 427 | 428 | 遍历数组,使用`Array.prototype.slice()`删除数组的最后一个元素,直到函数的返回值为`true`。返回剩余的元素。 429 | 430 | ```js 431 | const dropRightWhile = (arr, func) => { 432 | while (arr.length > 0 && !func(arr[arr.length - 1])) arr = arr.slice(0, -1); 433 | return arr; 434 | }; 435 | ``` 436 | 437 | 示例 438 | 439 | ```js 440 | dropRightWhile([1, 2, 3, 4], n => n < 3); // [1, 2] 441 | ``` 442 | 443 | ### dropWhile 444 | 445 | 移除数组中的元素,直到传递的函数返回`true`。返回数组中剩余的元素。 446 | 447 | 遍历数组,使用`Array.prototype.slice()`删除数组的第一个元素,直到函数的返回值为`true`。返回剩余的元素。 448 | 449 | ```js 450 | const dropWhile = (arr, func) => { 451 | while (arr.length > 0 && !func(arr[0])) arr = arr.slice(1); 452 | return arr; 453 | }; 454 | ``` 455 | 456 | 457 | 示例 458 | 459 | ```js 460 | dropWhile([1, 2, 3, 4], n => n >= 3); // [3,4] 461 | ``` 462 | 463 | ### everyNth 464 | 465 | 返回数组中所有下标是n的倍数的元素。 466 | 467 | 使用 `Array.prototype.filter()` 创建包含给定数组中所有下标是n的倍数的元素的新数组。 468 | 469 | ```js 470 | const everyNth = (arr, nth) => arr.filter((e, i) => i % nth === nth - 1); 471 | ``` 472 | 473 | 474 | 示例 475 | 476 | ```js 477 | everyNth([1, 2, 3, 4, 5, 6], 2); // [ 2, 4, 6 ] 478 | ``` 479 | 480 | 481 | ### filterFalsy 482 | 483 | 把数组中的`虚值`过滤掉。 484 | 485 | 使用 `Array.prototype.filter()`创建一个只包含`真值`的新数组。 486 | 487 | 488 | ```js 489 | const filterFalsy = arr => arr.filter(Boolean); 490 | ``` 491 | 492 | > `falsy`(虚值)是在` Boolean `上下文中已认定可转换为‘假‘的值。例如:false,0,"",null,undefined 和 NaN 。 493 | 494 | > `Truthy` (真值)指的是在 布尔值 上下文中转换后的值为真的值。所有值都是真值,除非它们被定义为 `falsy`。 495 | 496 | 示例 497 | 498 | ```js 499 | filterFalsy(['', true, {}, false, 'sample', 1, 0]); // [true, {}, 'sample', 1] 500 | ``` 501 | 502 | 503 | 504 | ### filterNonUnique 505 | 506 | 过滤调数组中重复的值。 507 | 508 | 使用 `Array.prototype.filter()`创建一个只包含唯一值的数组。 509 | 510 | ```js 511 | const filterNonUnique = arr => arr.filter(i => arr.indexOf(i) === arr.lastIndexOf(i)); 512 | ``` 513 | 514 | > filter() 方法创建一个新数组, 其包含通过所提供函数实现的测试的所有元素。 515 | 516 | > filter 不会改变原数组,它返回过滤后的新数组。 517 | 518 | 示例 519 | 520 | ```js 521 | filterNonUnique([1, 2, 2, 3, 4, 4, 5]); // [1, 3, 5] 522 | ``` 523 | 524 | 525 | ### filterNonUniqueBy 526 | 527 | 基于给定的比较器函数,过滤掉数组中重复的元素。 528 | 529 | 使用`Array.prototype.filter()` 和 `Array.prototype.every()` 创建一个新数组,该数组只包含唯一值,基于给定的比较器函数 `fn`。 530 | 531 | 比较器函数接收四个参数:正在被比较的两个元素和他们的索引。 532 | 533 | ```js 534 | const filterNonUniqueBy = (arr, fn) => 535 | arr.filter((v, i) => arr.every((x, j) => (i === j) === fn(v, x, i, j))); 536 | ``` 537 | 538 | 539 | 示例 540 | 541 | ```js 542 | filterNonUniqueBy( 543 | [ 544 | { id: 0, value: 'a' }, 545 | { id: 1, value: 'b' }, 546 | { id: 2, value: 'c' }, 547 | { id: 1, value: 'd' }, 548 | { id: 0, value: 'e' } 549 | ], 550 | (a, b) => a.id == b.id 551 | ); // [ { id: 2, value: 'c' } ] 552 | ``` 553 | 554 | 555 | ### findLast 556 | 557 | 返回所提供函数返回`真值`的最后一个元素。 558 | 559 | 使用 `Array.prototype.filter()` 将调用`fn`后返回`虚值`的元素过滤掉, 然后调用`Array.prototype.pop()` 来获取最后一个元素。 560 | 561 | ```js 562 | const findLast = (arr, fn) => arr.filter(fn).pop(); 563 | ``` 564 | 565 | 566 | 示例 567 | 568 | ```js 569 | findLast([1, 2, 3, 4], n => n % 2 === 1); // 3 570 | ``` 571 | 572 | 573 | 574 | ### findLastIndex 575 | 576 | 返回所提供函数返回`真值`的最后一个元素的索引。 577 | 578 | 使用 `Array.prototype.map()` 将每个元素映射到具有其索引和值的数组。 579 | 使用 `Array.prototype.filter()` 将调用`fn`后返回`虚值`的元素过滤掉, 然后调用`Array.prototype.pop()` 来获取最后一个元素的索引。 580 | 581 | ```js 582 | const findLastIndex = (arr, fn) => 583 | arr 584 | .map((val, i) => [i, val]) 585 | .filter(([i, val]) => fn(val, i, arr)) 586 | .pop()[0]; 587 | ``` 588 | 589 | 590 | 示例 591 | 592 | ```js 593 | findLastIndex([1, 2, 3, 4], n => n % 2 === 1); // 2 (index of the value 3) 594 | ``` 595 | 596 | 597 | ### flatten 598 | 599 | 根据指定的深度展平一个数组。 600 | 601 | 使用递归,每层递归 `depth` 递减1。 602 | 使用 `Array.prototype.reduce()` 和 `Array.prototype.concat()` 来合并数组或者元素。 603 | 基本情况下,当`depth` 等于1时停止递归。 604 | 忽略第二个参数的情况下, `depth` 默认为1(单层展开)。 605 | 606 | ```js 607 | const flatten = (arr, depth = 1) => 608 | arr.reduce((a, v) => a.concat(depth > 1 && Array.isArray(v) ? flatten(v, depth - 1) : v), []); 609 | ``` 610 | 611 | 612 | 示例 613 | 614 | ```js 615 | flatten([1, [2], 3, 4]); // [1, 2, 3, 4] 616 | flatten([1, [2, [3, [4, 5], 6], 7], 8], 2); // [1, 2, 3, [4, 5], 6, 7, 8] 617 | ``` 618 | 619 | 620 | ### forEachRight 621 | 622 | 对数组中的每个元素执行一次所提供的函数,从数组的最后一个元素开始。 623 | 624 | 625 | 使用 `Array.prototype.slice(0)` 克隆给定的数组,并使用`Array.prototype.reverse()` 将它反转,然后使用`Array.prototype.forEach()`遍历反转后的数组。 626 | 627 | ```js 628 | const forEachRight = (arr, callback) => 629 | arr 630 | .slice(0) 631 | .reverse() 632 | .forEach(callback); 633 | ``` 634 | 635 | 示例 636 | 637 | ```js 638 | forEachRight([1, 2, 3, 4], val => console.log(val)); // '4', '3', '2', '1' 639 | ``` 640 | 641 | 642 | ### groupBy 643 | 644 | 基于给定的函数将数组分组。 645 | 646 | 使用 `Array.prototype.map()` 将组数中的值映射到一个函数或者属性名。 647 | 648 | 使用 `Array.prototype.reduce()` 创建一个对象,其中的键由映射的结果生成。 649 | 650 | ```js 651 | const groupBy = (arr, fn) => 652 | arr.map(typeof fn === 'function' ? fn : val => val[fn]).reduce((acc, val, i) => { 653 | acc[val] = (acc[val] || []).concat(arr[i]); 654 | return acc; 655 | }, {}); 656 | ``` 657 | 658 | 659 | 示例 660 | 661 | ```js 662 | groupBy([6.1, 4.2, 6.3], Math.floor); // {4: [4.2], 6: [6.1, 6.3]} 663 | groupBy(['one', 'two', 'three'], 'length'); // {3: ['one', 'two'], 5: ['three']} 664 | ``` 665 | 666 | 667 | ### head 668 | 669 | 返回列表的头部 670 | 671 | 使用 `arr[0]` 返回传递数组的第一个元素。 672 | 673 | ```js 674 | const head = arr => arr[0]; 675 | ``` 676 | 677 | 678 | 示例 679 | 680 | ```js 681 | head([1, 2, 3]); // 1 682 | ``` 683 | 684 | 685 | 686 | ### indexOfAll 687 | 688 | 返回一个数组中所有 `val` 的索引。 689 | 如果 `val` 不存在,返回 `[]` 。 690 | 691 | 使用 `Array.prototype.reduce()` 遍历元素,将匹配的元素索引存储下来,返回索引数组。 692 | 693 | ```js 694 | const indexOfAll = (arr, val) => arr.reduce((acc, el, i) => (el === val ? [...acc, i] : acc), []); 695 | ``` 696 | 697 | 698 | 示例 699 | 700 | ```js 701 | indexOfAll([1, 2, 3, 1, 2, 3], 1); // [0,3] 702 | indexOfAll([1, 2, 3], 4); // [] 703 | ``` 704 | 705 | 706 | ### initial 707 | 708 | 返回数组中除最后一个元素外的所有元素。 709 | 710 | 使用 `arr.slice(0,-1)` 返回数组中除最后一个元素外的所有元素。 711 | 712 | ```js 713 | const initial = arr => arr.slice(0, -1); 714 | ``` 715 | 716 | 717 | 示例 718 | 719 | ```js 720 | initial([1, 2, 3]); // [1,2] 721 | ``` 722 | 723 | 724 | ### initialize2DArray 725 | 726 | 根据给定的宽、高和值初始化一个二维数组。 727 | 728 | 使用 `Array.prototype.map()` 生成`h`行,其中每一行都是大小为`w`的新数组,并用值初始化。如果没有提供该值,则默认为`null`。 729 | 730 | 731 | ```js 732 | const initialize2DArray = (w, h, val = null) => 733 | Array.from({ length: h }).map(() => Array.from({ length: w }).fill(val)); 734 | ``` 735 | 736 | > Array.from() 可以通过以下方式来创建数组对象: 737 | > 738 | >- 伪数组对象(拥有一个 length 属性和若干索引属性的任意对象) 例: `Array.from({ length: 10 })` 739 | >- 可迭代对象(可以获取对象中的元素,如 Map和 Set 等) 740 | 741 | 示例 742 | 743 | ```js 744 | initialize2DArray(2, 2, 0); // [[0,0], [0,0]] 745 | ``` 746 | 747 | 748 | ### initializeArrayWithRange 749 | 750 | 初始化一个数组,该数组包括从 `start` 到 `end` 指定范围的数字,并且包括共同的公差 `step` 。 751 | 752 | 使用 `Array.from()` 创建一个所需长度 `(end - start + 1)/step` 的数组,然后指定一个匹配函数将指定范围内的所需值填充到数组中。 753 | 754 | 你可以省略 `start` 使用默认值`0`。 755 | 你可以省略 `step` 使用默认值`1`。 756 | 757 | ```js 758 | const initializeArrayWithRange = (end, start = 0, step = 1) => 759 | Array.from({ length: Math.ceil((end - start + 1) / step) }, (v, i) => i * step + start); 760 | ``` 761 | 762 | > `Array.from()` 方法有一个可选参数 mapFn,让你可以在最后生成的数组上再执行一次 `map `方法后再返回。也就是说 `Array.from(obj, mapFn, thisArg)` 就相当于` Array.from(obj).map(mapFn, thisArg)`。 763 | 764 | 示例 765 | 766 | ```js 767 | initializeArrayWithRange(5); // [0,1,2,3,4,5] 768 | initializeArrayWithRange(7, 3); // [3,4,5,6,7] 769 | initializeArrayWithRange(9, 0, 2); // [0,2,4,6,8] 770 | ``` 771 | 772 | 773 | ### initializeArrayWithRangeRight 774 | 775 | 初始化一个数组,该数组包括从 `start` 到 `end` 指定范围的数字(反向的),并且包括共同的公差 `step` 。 776 | 777 | 使用 `Array.from(Math.ceil((end+1-start)/step))` 创建一个期望长度的数组(为了兼容结束,元素的数量等同于`(end-start)/step` 或 `(end+1-start)/step`),使用`Array.prototype.map()`来填充期望范围内的值。 778 | 779 | 你可以省略 `start` 使用默认值`0`。 780 | 你可以省略 `step` 使用默认值`1`。 781 | 782 | ```js 783 | const initializeArrayWithRangeRight = (end, start = 0, step = 1) => 784 | Array.from({ length: Math.ceil((end + 1 - start) / step) }).map( 785 | (v, i, arr) => (arr.length - i - 1) * step + start 786 | ); 787 | ``` 788 | 789 | 790 | 示例 791 | 792 | ```js 793 | initializeArrayWithRangeRight(5); // [5,4,3,2,1,0] 794 | initializeArrayWithRangeRight(7, 3); // [7,6,5,4,3] 795 | initializeArrayWithRangeRight(9, 0, 2); // [8,6,4,2,0] 796 | ``` 797 | 798 | 799 | ### initializeArrayWithValues 800 | 801 | 初始化一个数组,并且使用指定的值填充它。 802 | 803 | 使用 `Array(n)` 创建一个期望长度的数组,使用 `fill(v)` 用期望的值填充数组。 804 | 805 | 你可以省略参数 `val` 使用默认值`0`。 806 | 807 | ```js 808 | const initializeArrayWithValues = (n, val = 0) => Array(n).fill(val); 809 | ``` 810 | 811 | 812 | 示例 813 | 814 | ```js 815 | initializeArrayWithValues(5, 2); // [2, 2, 2, 2, 2] 816 | ``` 817 | 818 | 819 | ### initializeNDArray 820 | 821 | 使用给定的值创建一个n维数组。 822 | 823 | 使用递归。使用 `Array.prototype.map()` 来生成行,这些行每一个都是使用`initializeNDArray`初始化的新数组。 824 | 825 | ```js 826 | const initializeNDArray = (val, ...args) => 827 | args.length === 0 828 | ? val 829 | : Array.from({ length: args[0] }).map(() => initializeNDArray(val, ...args.slice(1))); 830 | ``` 831 | 832 | 833 | 示例 834 | 835 | ```js 836 | initializeNDArray(1, 3); // [1,1,1] 837 | initializeNDArray(5, 2, 2, 2); // [[[5,5],[5,5]],[[5,5],[5,5]]] 838 | ``` 839 | 840 | ### intersection 841 | 842 | 返回两个数组中都存在的元素列表。 843 | 844 | 从 `b`创建一个 `Set` ,然后在`a`上使用`Array.prototype.filter()`来只保留 `b`中包含的元素。 845 | 846 | ```js 847 | const intersection = (a, b) => { 848 | const s = new Set(b); 849 | return a.filter(x => s.has(x)); 850 | }; 851 | ``` 852 | 853 | 示例 854 | 855 | ```js 856 | intersection([1, 2, 3], [4, 3, 2]); // [2, 3] 857 | ``` 858 | 859 | ### intersectionBy 860 | 861 | 将提供的函数应应用到两个数组的每个元素上,然后返回两个数组中都存在的元素列表 862 | 863 | 通过将 `fn` 应用到 `b`的所有元素来创建一个 `Set`,然后在 `a` 上调用 `Array.prototype.filter()` 来只保留调用 `fn` 后 `b` 中包含的元素。 864 | 865 | ```js 866 | const intersectionBy = (a, b, fn) => { 867 | const s = new Set(b.map(fn)); 868 | return a.filter(x => s.has(fn(x))); 869 | }; 870 | ``` 871 | 872 | 873 | 示例 874 | 875 | ```js 876 | intersectionBy([2.1, 1.2], [2.3, 3.4], Math.floor); // [2.1] 877 | ``` 878 | 879 | 880 | ### intersectionWith 881 | 882 | 返回两个数组中都存在的元素列表,使用给定的比较函数。 883 | 884 | 结合使用`Array.prototype.filter()`和 `Array.prototype.findIndex()` 来确定交叉值。 885 | 886 | ```js 887 | const intersectionWith = (a, b, comp) => a.filter(x => b.findIndex(y => comp(x, y)) !== -1); 888 | ``` 889 | 890 | > findIndex()方法返回数组中满足提供的测试函数的第一个元素的索引。否则返回-1。 891 | 892 | 示例 893 | 894 | ```js 895 | intersectionWith([1, 1.2, 1.5, 3, 0], [1.9, 3, 0, 3.9], (a, b) => Math.round(a) === Math.round(b)); // [1.5, 3, 0] 896 | ``` 897 | 898 | 899 | ### isSorted 900 | 901 | 如果数组是升序排序的,返回 `1` ,如果数组是降序排序的返回 `-1`,如果数组没有排序返回`0` 。 902 | 903 | 计算前两个元素的顺序 `direction`。使用 `Object.entries()` 来遍历数组,病成对比较。如果 `direction` 改变,返回 `0` ,如果到达最后一个元素,返回 `direction` 。 904 | 905 | 906 | ```js 907 | const isSorted = arr => { 908 | let direction = -(arr[0] - arr[1]); 909 | for (let [i, val] of arr.entries()) { 910 | direction = !direction ? -(arr[i - 1] - arr[i]) : direction; 911 | if (i === arr.length - 1) return !direction ? 0 : direction; 912 | else if ((val - arr[i + 1]) * direction > 0) return 0; 913 | } 914 | }; 915 | ``` 916 | > entries() 方法返回一个新的Array Iterator对象,该对象包含数组中每个索引的键/值对。 917 | 918 | > 下面是使用 for…of 循环的示例 919 | 920 | ```js 921 | var arr = ["a", "b", "c"]; 922 | for (let e of arr.entries()) { 923 | console.log(e); 924 | } 925 | // [0, "a"] 926 | // [1, "b"] 927 | // [2, "c"] 928 | ``` 929 | 930 | 示例 931 | 932 | ```js 933 | isSorted([0, 1, 2, 2]); // 1 934 | isSorted([4, 3, 2]); // -1 935 | isSorted([4, 3, 5]); // 0 936 | ``` 937 | 938 | 939 | ### join 940 | 941 | 将数组中所有的元素连接成一个字符串,并返回这个字符串。使用一个分隔符和结束分隔符。 942 | 943 | 944 | 使用 `Array.prototype.reduce()` 将元素合并成字符串。 945 | 忽略第二个参数,`separator`,默认情况下使用一个默认分隔符`','`。 946 | 忽略第三个参数, `end`,使用和`separator`相同的值作为默认值。 947 | 948 | ```js 949 | const join = (arr, separator = ',', end = separator) => 950 | arr.reduce( 951 | (acc, val, i) => 952 | i === arr.length - 2 953 | ? acc + val + end 954 | : i === arr.length - 1 955 | ? acc + val 956 | : acc + val + separator, 957 | '' 958 | ); 959 | ``` 960 | 961 | 962 | 示例 963 | 964 | ```js 965 | join(['pen', 'pineapple', 'apple', 'pen'], ',', '&'); // "pen,pineapple,apple&pen" 966 | join(['pen', 'pineapple', 'apple', 'pen'], ','); // "pen,pineapple,apple,pen" 967 | join(['pen', 'pineapple', 'apple', 'pen']); // "pen,pineapple,apple,pen" 968 | ``` 969 | 970 | 971 | 972 | 973 | 974 | ### JSONtoCSV 975 | 976 | 977 | 将对象数组转换为仅包含指定的`columns`的逗号分隔值`(CSV)`字符串。 978 | 979 | 使用 `Array.prototype.join(delimiter)` 合并`columns`中的所有名称以创建第一行。、 980 | 981 | 使用 `Array.prototype.map()` 和 `Array.prototype.reduce()` 为每个对象创建一行,用空字符串替换不存在的值,只映射“列”中的值。 982 | 983 | 使用` Array.prototype.join('\n') `将所有行组合成一个字符串。 984 | 忽略第三个参数 `delimiter`,使用默认分隔符 `,`。 985 | 986 | ```js 987 | const JSONtoCSV = (arr, columns, delimiter = ',') => 988 | [ 989 | columns.join(delimiter), 990 | ...arr.map(obj => 991 | columns.reduce( 992 | (acc, key) => `${acc}${!acc.length ? '' : delimiter}"${!obj[key] ? '' : obj[key]}"`, 993 | '' 994 | ) 995 | ) 996 | ].join('\n'); 997 | ``` 998 | 999 | 1000 | 示例 1001 | 1002 | ```js 1003 | JSONtoCSV([{ a: 1, b: 2 }, { a: 3, b: 4, c: 5 }, { a: 6 }, { b: 7 }], ['a', 'b']); // 'a,b\n"1","2"\n"3","4"\n"6",""\n"","7"' 1004 | JSONtoCSV([{ a: 1, b: 2 }, { a: 3, b: 4, c: 5 }, { a: 6 }, { b: 7 }], ['a', 'b'], ';'); // 'a;b\n"1";"2"\n"3";"4"\n"6";""\n"";"7"' 1005 | ``` 1006 | 1007 | 1008 | ### last 1009 | 1010 | 返回数组中最后一个元素。 1011 | 1012 | 使用 `arr.length - 1` 来计算给定数组最后一个元素的索引,然后返回它。 1013 | 1014 | ```js 1015 | const last = arr => arr[arr.length - 1]; 1016 | ``` 1017 | 1018 | 1019 | 示例 1020 | 1021 | ```js 1022 | last([1, 2, 3]); // 3 1023 | ``` 1024 | 1025 | 1026 | ### longestItem 1027 | 1028 | 获取任意数量的可迭代对象或具有 `length` 属性的对象,并返回其中最长的一个。 1029 | 1030 | 如果多个对象具有相同的长度,则返回第一个对象。 1031 | 如果没有提供参数,则返回“undefined”。 1032 | 1033 | 使用` Array.prototype.reduce() `,比较对象的` length `以找到最长的对象。 1034 | 1035 | ```js 1036 | const longestItem = (...vals) => vals.reduce((a, x) => (x.length > a.length ? x : a)); 1037 | ``` 1038 | 1039 | 示例 1040 | 1041 | ```js 1042 | longestItem('this', 'is', 'a', 'testcase'); // 'testcase' 1043 | longestItem(...['a', 'ab', 'abc']); // 'abc' 1044 | longestItem(...['a', 'ab', 'abc'], 'abcd'); // 'abcd' 1045 | longestItem([1, 2, 3], [1, 2], [1, 2, 3, 4, 5]); // [1, 2, 3, 4, 5] 1046 | longestItem([1, 2, 3], 'foobar'); // 'foobar' 1047 | ``` 1048 | 1049 | ### mapObject 1050 | 1051 | 使用函数将数组的值映射到对象,其中键值对由作为键的原始值和映射的值组成。 1052 | 1053 | 使用匿名内部函数作用域声明未定义的内存空间,使用闭包存储返回值。使用一个新的 `Array` 来存储数组,其中包含函数在其数据集上的映射,并使用逗号操作符返回第二个步骤,而不需要从一个上下文移动到另一个上下文(由于闭包和操作顺序)。 1054 | 1055 | ```js 1056 | const mapObject = (arr, fn) => 1057 | (a => ( 1058 | (a = [arr, arr.map(fn)]), a[0].reduce((acc, val, ind) => ((acc[val] = a[1][ind]), acc), {}) 1059 | ))(); 1060 | ``` 1061 | 1062 | 1063 | 示例 1064 | 1065 | ```js 1066 | const squareIt = arr => mapObject(arr, a => a * a); 1067 | squareIt([1, 2, 3]); // { 1: 1, 2: 4, 3: 9 } 1068 | ``` 1069 | 1070 | 1071 | ### maxN 1072 | 1073 | 返回给定数组中前 `n` 大的元素。 1074 | 如果 `n` 比给定的数组长度还要大,返回原始数组(按降序排列)。 1075 | 1076 | 使用 `Array.prototype.sort()` 结合展开操作符 (`...`) 创建一个数组的浅克隆,并按照降序排序。 1077 | 使用 `Array.prototype.slice()` 获取指定数量的元素。 1078 | 忽略第二个参数, `n`, 返回一个单元素数组。 1079 | 1080 | ```js 1081 | const maxN = (arr, n = 1) => [...arr].sort((a, b) => b - a).slice(0, n); 1082 | ``` 1083 | 1084 | 1085 | 示例 1086 | 1087 | ```js 1088 | maxN([1, 2, 3]); // [3] 1089 | maxN([1, 2, 3], 2); // [3,2] 1090 | ``` 1091 | 1092 | 1093 | ### minN 1094 | 1095 | 返回给定数组中前 `n` 小的元素。 1096 | 如果 `n` 比给定的数组长度还要大,返回原始数组(按升序排列)。 1097 | 1098 | 使用 `Array.prototype.sort()` 结合展开操作符 (`...`) 创建一个数组的浅克隆,并按照升序排序。 1099 | 使用 `Array.prototype.slice()` 获取指定数量的元素。 1100 | 忽略第二个参数, `n`, 返回一个单元素数组。 1101 | 1102 | ```js 1103 | const minN = (arr, n = 1) => [...arr].sort((a, b) => a - b).slice(0, n); 1104 | ``` 1105 | 1106 | 示例 1107 | 1108 | ```js 1109 | minN([1, 2, 3]); // [1] 1110 | minN([1, 2, 3], 2); // [1,2] 1111 | ``` 1112 | 1113 | ### none 1114 | 1115 | 如果对集合中所有的元素执行判定函数全部都返回`false`,那么函数返回`true`,否则返回`false`。 1116 | 1117 | 基于`fn`使用`Array.prototype.some()`来测试是否集合中有任意一个元素返回`true`。 1118 | 1119 | 忽略第二个参数,`fn`,使用`Boolean`作为默认值。 1120 | 1121 | ```js 1122 | const none = (arr, fn = Boolean) => !arr.some(fn); 1123 | ``` 1124 | 1125 | 1126 | 示例 1127 | 1128 | ```js 1129 | none([0, 1, 3, 0], x => x == 2); // true 1130 | none([0, 0, 0]); // true 1131 | ``` 1132 | 1133 | 1134 | ### nthElement 1135 | 1136 | 返回数组中第`n`个元素(`n`可以是负数)。 1137 | 1138 | 使用`Array.prototype.slice()`获得在首位包含第`n`个元素的数组。 1139 | 1140 | 如果下标越界,返回`undefined`。 1141 | 1142 | 如果没有第二个参数,`n`,返回数组中第一个元素。 1143 | 1144 | ```js 1145 | const nthElement = (arr, n = 0) => (n === -1 ? arr.slice(n) : arr.slice(n, n + 1))[0]; 1146 | ``` 1147 | 1148 | 1149 | 示例 1150 | 1151 | ```js 1152 | nthElement(['a', 'b', 'c'], 1); // 'b' 1153 | nthElement(['a', 'b', 'b'], -3); // 'a' 1154 | ``` 1155 | 1156 | 1157 | 1158 | ### offset 1159 | 1160 | 将指定数量的元素移动到数组的末尾。 1161 | 1162 | 使用 `Array.prototype.slice()` 两次来获取指定索引后面的元素和前面的元素。 1163 | 1164 | 使用扩展操作符(`...`)将两个数组合并成一个数组。 1165 | 1166 | 如果`offset`是负,元素将被从末尾移动到开始。 1167 | 1168 | ```js 1169 | const offset = (arr, offset) => [...arr.slice(offset), ...arr.slice(0, offset)]; 1170 | ``` 1171 | 1172 | 示例 1173 | 1174 | ```js 1175 | offset([1, 2, 3, 4, 5], 2); // [3, 4, 5, 1, 2] 1176 | offset([1, 2, 3, 4, 5], -2); // [4, 5, 1, 2, 3] 1177 | ``` 1178 | 1179 | 1180 | ### partition 1181 | 1182 | 根据提供的函数对每个元素的真实性,将元素分组为两个数组。 1183 | 1184 | 使用`Array.prototype.reduce()`创建一个由两个数组组成的数组。 1185 | 1186 | 使用`Array.prototype.push()`将执行`fn`返回`true`的元素添加到第一个数组,执行`fn`返回`false`的元素添加到第二个数组。 1187 | 1188 | ```js 1189 | const partition = (arr, fn) => 1190 | arr.reduce( 1191 | (acc, val, i, arr) => { 1192 | acc[fn(val, i, arr) ? 0 : 1].push(val); 1193 | return acc; 1194 | }, 1195 | [[], []] 1196 | ); 1197 | ``` 1198 | 1199 | 1200 | 示例 1201 | 1202 | ```js 1203 | const users = [{ user: 'barney', age: 36, active: false }, { user: 'fred', age: 40, active: true }]; 1204 | partition(users, o => o.active); // [[{ 'user': 'fred', 'age': 40, 'active': true }],[{ 'user': 'barney', 'age': 36, 'active': false }]] 1205 | ``` 1206 | 1207 | ### permutations 1208 | 1209 | 生成数组元素的所有排列(包括重复元素) 1210 | 1211 | 使用递归。 1212 | 1213 | 对于给定数组中的每个元素,为其其余元素创建所有部分排列。 1214 | 1215 | 使用`Array.prototype.map()`组合每个元素的部分排列,然后使用`Array.prototype.reduce()`组合一个数组中的所有排列。 1216 | 1217 | 基本情况是数组`length` 等于 `2` 或 `1`。 1218 | 1219 | ```js 1220 | const permutations = arr => { 1221 | if (arr.length <= 2) return arr.length === 2 ? [arr, [arr[1], arr[0]]] : arr; 1222 | return arr.reduce( 1223 | (acc, item, i) => 1224 | acc.concat( 1225 | permutations([...arr.slice(0, i), ...arr.slice(i + 1)]).map(val => [item, ...val]) 1226 | ), 1227 | [] 1228 | ); 1229 | }; 1230 | ``` 1231 | 1232 | 1233 | 示例 1234 | 1235 | ```js 1236 | permutations([1, 33, 5]); // [ [ 1, 33, 5 ], [ 1, 5, 33 ], [ 33, 1, 5 ], [ 33, 5, 1 ], [ 5, 1, 33 ], [ 5, 33, 1 ] ] 1237 | ``` 1238 | 1239 | 1240 | 1241 | ### pull 1242 | 1243 | 修改原始数组,以过滤掉指定的值。 1244 | 1245 | 使用`Array.prototype.filter()` 和 `Array.prototype.includes()`将不需要过滤的值提取出来。 1246 | 1247 | 使用`Array.prototype。length = 0 `通过将数组的长度重置为`0`来改变数组中传递的值,并使用` array .prototype.push() `仅用提取的值重新填充数组。 1248 | 1249 | ```js 1250 | const pull = (arr, ...args) => { 1251 | let argState = Array.isArray(args[0]) ? args[0] : args; 1252 | let pulled = arr.filter((v, i) => !argState.includes(v)); 1253 | arr.length = 0; 1254 | pulled.forEach(v => arr.push(v)); 1255 | }; 1256 | ``` 1257 | 1258 | 示例 1259 | 1260 | ```js 1261 | let myArray = ['a', 'b', 'c', 'a', 'b', 'c']; 1262 | pull(myArray, 'a', 'c'); // myArray = [ 'b', 'b' ] 1263 | ``` 1264 | 1265 | 1266 | ### pullAtIndex 1267 | 1268 | 修改原始数组,以过滤指定索引处的值。 1269 | 1270 | 使用`Array.prototype.filter()` 和 `Array.prototype.includes()`将不需要过滤的值提取出来。 1271 | 1272 | 使用`Array.prototype。length = 0 `通过将数组的长度重置为`0`来改变数组中传递的值,并使用` array .prototype.push() `仅用提取的值重新填充数组。 1273 | 1274 | ```js 1275 | const pullAtIndex = (arr, pullArr) => { 1276 | let removed = []; 1277 | let pulled = arr 1278 | .map((v, i) => (pullArr.includes(i) ? removed.push(v) : v)) 1279 | .filter((v, i) => !pullArr.includes(i)); 1280 | arr.length = 0; 1281 | pulled.forEach(v => arr.push(v)); 1282 | return removed; 1283 | }; 1284 | ``` 1285 | 1286 | 1287 | 示例 1288 | 1289 | ```js 1290 | let myArray = ['a', 'b', 'c', 'd']; 1291 | let pulled = pullAtIndex(myArray, [1, 3]); // myArray = [ 'a', 'c' ] , pulled = [ 'b', 'd' ] 1292 | ``` 1293 | 1294 | 1295 | ### pullAtValue 1296 | 1297 | 1298 | 修改原始数组,以过滤掉指定的值。返回移除后的元素。 1299 | 1300 | 使用`Array.prototype.filter()` 和 `Array.prototype.includes()`将不需要过滤的值提取出来。 1301 | 1302 | 使用`Array.prototype。length = 0 `通过将数组的长度重置为`0`来改变数组中传递的值,并使用` array .prototype.push() `仅用提取的值重新填充数组。 1303 | 1304 | 使用`Array.prototype.push() `跟踪拉取出来的值。 1305 | 1306 | ```js 1307 | const pullAtValue = (arr, pullArr) => { 1308 | let removed = [], 1309 | pushToRemove = arr.forEach((v, i) => (pullArr.includes(v) ? removed.push(v) : v)), 1310 | mutateTo = arr.filter((v, i) => !pullArr.includes(v)); 1311 | arr.length = 0; 1312 | mutateTo.forEach(v => arr.push(v)); 1313 | return removed; 1314 | }; 1315 | ``` 1316 | 1317 | 1318 | 示例 1319 | 1320 | ```js 1321 | let myArray = ['a', 'b', 'c', 'd']; 1322 | let pulled = pullAtValue(myArray, ['b', 'd']); // myArray = [ 'a', 'c' ] , pulled = [ 'b', 'd' ] 1323 | ``` 1324 | 1325 | 1326 | ### reducedFilter 1327 | 1328 | 根据一个条件过滤对象数组,同时过滤掉未指定的键。 1329 | 1330 | 使用`Array.prototype.filter()`根据判定函数`fn`对数组进行过滤,返回条件返回`true`值的对象。 1331 | 1332 | 在过滤后的数组的基础上,使用 `Array.prototype.map()` 返回使用 `Array.prototype.reduce()` 将不在参数`keys`中的属性过滤掉后的新对象。 1333 | 1334 | ```js 1335 | const reducedFilter = (data, keys, fn) => 1336 | data.filter(fn).map(el => 1337 | keys.reduce((acc, key) => { 1338 | acc[key] = el[key]; 1339 | return acc; 1340 | }, {}) 1341 | ); 1342 | ``` 1343 | 1344 | 示例 1345 | 1346 | ```js 1347 | const data = [ 1348 | { 1349 | id: 1, 1350 | name: 'john', 1351 | age: 24 1352 | }, 1353 | { 1354 | id: 2, 1355 | name: 'mike', 1356 | age: 50 1357 | } 1358 | ]; 1359 | 1360 | reducedFilter(data, ['id', 'name'], item => item.age > 24); // [{ id: 2, name: 'mike'}] 1361 | ``` 1362 | 1363 | 1364 | ### reduceSuccessive 1365 | 1366 | 对累加器和数组中的每个元素应用一个函数(从左到右),返回一个依次递减的值数组。 1367 | 1368 | 使用`Array.prototype.reduce()` 将给定函数应用于给定数组,存储每个新结果。 1369 | 1370 | ```js 1371 | const reduceSuccessive = (arr, fn, acc) => 1372 | arr.reduce((res, val, i, arr) => (res.push(fn(res.slice(-1)[0], val, i, arr)), res), [acc]); 1373 | ``` 1374 | 1375 | 1376 | 示例 1377 | 1378 | ```js 1379 | reduceSuccessive([1, 2, 3, 4, 5, 6], (acc, val) => acc + val, 0); // [0, 1, 3, 6, 10, 15, 21] 1380 | ``` 1381 | 1382 | 1383 | 1384 | ### reduceWhich 1385 | 1386 | 将给定的函数设置比较规则后,返回数组的最小/最大值。 1387 | 1388 | 结合使用`Array.prototype.reduce()` 和 `comparator`函数,以获取数组中的适当元素。 1389 | 1390 | 你可以省略第二个参数, `comparator`,使用返回数组中最小元素的默认值。 1391 | 1392 | ```js 1393 | const reduceWhich = (arr, comparator = (a, b) => a - b) => 1394 | arr.reduce((a, b) => (comparator(a, b) >= 0 ? b : a)); 1395 | ``` 1396 | 1397 | 1398 | 示例 1399 | 1400 | ```js 1401 | reduceWhich([1, 3, 2]); // 1 1402 | reduceWhich([1, 3, 2], (a, b) => b - a); // 3 1403 | reduceWhich( 1404 | [{ name: 'Tom', age: 12 }, { name: 'Jack', age: 18 }, { name: 'Lucy', age: 9 }], 1405 | (a, b) => a.age - b.age 1406 | ); // {name: "Lucy", age: 9} 1407 | ``` 1408 | 1409 | 1410 | 1411 | ### reject 1412 | 1413 | 1414 | 接受一个判定函数和一个数组,像`Array.prototype.filter()`一样,但是仅仅当`pred(x) === false`才保留`x` 。 1415 | 1416 | ```js 1417 | const reject = (pred, array) => array.filter((...args) => !pred(...args)); 1418 | ``` 1419 | 1420 | 1421 | 示例 1422 | 1423 | ```js 1424 | reject(x => x % 2 === 0, [1, 2, 3, 4, 5]); // [1, 3, 5] 1425 | reject(word => word.length > 4, ['Apple', 'Pear', 'Kiwi', 'Banana']); // ['Pear', 'Kiwi'] 1426 | ``` 1427 | 1428 | 1429 | ### remove 1430 | 1431 | Removes elements from an array for which the given function returns `false`. 1432 | 1433 | Use `Array.prototype.filter()` to find array elements that return truthy values and `Array.prototype.reduce()` to remove elements using `Array.prototype.splice()`. 1434 | The `func` is invoked with three arguments (`value, index, array`). 1435 | 1436 | ```js 1437 | 1438 | const remove = (arr, func) => 1439 | Array.isArray(arr) 1440 | ? arr.filter(func).reduce((acc, val) => { 1441 | arr.splice(arr.indexOf(val), 1); 1442 | return acc.concat(val); 1443 | }, []) 1444 | : []; 1445 | ``` 1446 | 1447 | 1448 | 示例 1449 | 1450 | ```js 1451 | remove([1, 2, 3, 4], n => n % 2 === 0); // [2, 4] 1452 | ``` 1453 | 1454 | 1455 | 1456 | 1457 | 1458 | ### sample 1459 | 1460 | Returns a random element from an array. 1461 | 1462 | Use `Math.random()` to generate a random number, multiply it by `length` and round it off to the nearest whole number using `Math.floor()`. 1463 | This method also works with strings. 1464 | 1465 | ```js 1466 | const sample = arr => arr[Math.floor(Math.random() * arr.length)]; 1467 | ``` 1468 | 1469 | 1470 | 示例 1471 | 1472 | ```js 1473 | sample([3, 7, 9, 11]); // 9 1474 | ``` 1475 | 1476 | 1477 | 1478 | 1479 | 1480 | ### sampleSize 1481 | 1482 | Gets `n` random elements at unique keys from `array` up to the size of `array`. 1483 | 1484 | Shuffle the array using the [Fisher-Yates algorithm](https://github.com/30-seconds/30-seconds-of-code#shuffle). 1485 | Use `Array.prototype.slice()` to get the first `n` elements. 1486 | Omit the second argument, `n` to get only one element at random from the array. 1487 | 1488 | ```js 1489 | const sampleSize = ([...arr], n = 1) => { 1490 | let m = arr.length; 1491 | while (m) { 1492 | const i = Math.floor(Math.random() * m--); 1493 | [arr[m], arr[i]] = [arr[i], arr[m]]; 1494 | } 1495 | return arr.slice(0, n); 1496 | }; 1497 | ``` 1498 | 1499 | 1500 | 示例 1501 | 1502 | ```js 1503 | sampleSize([1, 2, 3], 2); // [3,1] 1504 | sampleSize([1, 2, 3], 4); // [2,3,1] 1505 | ``` 1506 | 1507 | 1508 | 1509 | 1510 | 1511 | ### shank 1512 | 1513 | Has the same functionality as [`Array.prototype.splice()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/splice), but returning a new array instead of mutating the original array. 1514 | 1515 | Use `Array.prototype.slice()` and `Array.prototype.concat()` to get a new array with the new contents after removing existing elements and/or adding new elements. 1516 | Omit the second argument, `index`, to start at `0`. 1517 | Omit the third argument, `delCount`, to remove `0` elements. 1518 | Omit the fourth argument, `elements`, in order to not add any new elements. 1519 | 1520 | ```js 1521 | const shank = (arr, index = 0, delCount = 0, ...elements) => 1522 | arr 1523 | .slice(0, index) 1524 | .concat(elements) 1525 | .concat(arr.slice(index + delCount)); 1526 | ``` 1527 | 1528 | 1529 | 示例 1530 | 1531 | ```js 1532 | const names = ['alpha', 'bravo', 'charlie']; 1533 | const namesAndDelta = shank(names, 1, 0, 'delta'); // [ 'alpha', 'delta', 'bravo', 'charlie' ] 1534 | const namesNoBravo = shank(names, 1, 1); // [ 'alpha', 'charlie' ] 1535 | console.log(names); // ['alpha', 'bravo', 'charlie'] 1536 | ``` 1537 | 1538 | 1539 | 1540 | 1541 | 1542 | ### shuffle 1543 | 1544 | Randomizes the order of the values of an array, returning a new array. 1545 | 1546 | Uses the [Fisher-Yates algorithm](https://github.com/30-seconds/30-seconds-of-code#shuffle) to reorder the elements of the array. 1547 | 1548 | ```js 1549 | const shuffle = ([...arr]) => { 1550 | let m = arr.length; 1551 | while (m) { 1552 | const i = Math.floor(Math.random() * m--); 1553 | [arr[m], arr[i]] = [arr[i], arr[m]]; 1554 | } 1555 | return arr; 1556 | }; 1557 | ``` 1558 | 1559 | 1560 | 示例 1561 | 1562 | ```js 1563 | const foo = [1, 2, 3]; 1564 | shuffle(foo); // [2, 3, 1], foo = [1, 2, 3] 1565 | ``` 1566 | 1567 | 1568 | 1569 | 1570 | 1571 | ### similarity 1572 | 1573 | Returns an array of elements that appear in both arrays. 1574 | 1575 | Use `Array.prototype.filter()` to remove values that are not part of `values`, determined using `Array.prototype.includes()`. 1576 | 1577 | ```js 1578 | const similarity = (arr, values) => arr.filter(v => values.includes(v)); 1579 | ``` 1580 | 1581 | 1582 | 示例 1583 | 1584 | ```js 1585 | similarity([1, 2, 3], [1, 2, 4]); // [1, 2] 1586 | ``` 1587 | 1588 | 1589 | 1590 | 1591 | 1592 | ### sortedIndex 1593 | 1594 | Returns the lowest index at which value should be inserted into array in order to maintain its sort order. 1595 | 1596 | Check if the array is sorted in descending order (loosely). 1597 | Use `Array.prototype.findIndex()` to find the appropriate index where the element should be inserted. 1598 | 1599 | ```js 1600 | const sortedIndex = (arr, n) => { 1601 | const isDescending = arr[0] > arr[arr.length - 1]; 1602 | const index = arr.findIndex(el => (isDescending ? n >= el : n <= el)); 1603 | return index === -1 ? arr.length : index; 1604 | }; 1605 | ``` 1606 | 1607 | 1608 | 示例 1609 | 1610 | ```js 1611 | sortedIndex([5, 3, 2, 1], 4); // 1 1612 | sortedIndex([30, 50], 40); // 1 1613 | ``` 1614 | 1615 | 1616 | 1617 | 1618 | 1619 | ### sortedIndexBy 1620 | 1621 | Returns the lowest index at which value should be inserted into array in order to maintain its sort order, based on a provided iterator function. 1622 | 1623 | Check if the array is sorted in descending order (loosely). 1624 | Use `Array.prototype.findIndex()` to find the appropriate index where the element should be inserted, based on the iterator function `fn`. 1625 | 1626 | ```js 1627 | const sortedIndexBy = (arr, n, fn) => { 1628 | const isDescending = fn(arr[0]) > fn(arr[arr.length - 1]); 1629 | const val = fn(n); 1630 | const index = arr.findIndex(el => (isDescending ? val >= fn(el) : val <= fn(el))); 1631 | return index === -1 ? arr.length : index; 1632 | }; 1633 | ``` 1634 | 1635 | 1636 | 示例 1637 | 1638 | ```js 1639 | sortedIndexBy([{ x: 4 }, { x: 5 }], { x: 4 }, o => o.x); // 0 1640 | ``` 1641 | 1642 | 1643 | 1644 | 1645 | 1646 | ### sortedLastIndex 1647 | 1648 | Returns the highest index at which value should be inserted into array in order to maintain its sort order. 1649 | 1650 | Check if the array is sorted in descending order (loosely). 1651 | Use `Array.prototype.reverse()` and `Array.prototype.findIndex()` to find the appropriate last index where the element should be inserted. 1652 | 1653 | ```js 1654 | const sortedLastIndex = (arr, n) => { 1655 | const isDescending = arr[0] > arr[arr.length - 1]; 1656 | const index = arr.reverse().findIndex(el => (isDescending ? n <= el : n >= el)); 1657 | return index === -1 ? 0 : arr.length - index; 1658 | }; 1659 | ``` 1660 | 1661 | 1662 | 示例 1663 | 1664 | ```js 1665 | sortedLastIndex([10, 20, 30, 30, 40], 30); // 4 1666 | ``` 1667 | 1668 | 1669 | 1670 | 1671 | 1672 | ### sortedLastIndexBy 1673 | 1674 | Returns the highest index at which value should be inserted into array in order to maintain its sort order, based on a provided iterator function. 1675 | 1676 | Check if the array is sorted in descending order (loosely). 1677 | Use `Array.prototype.map()` to apply the iterator function to all elements of the array. 1678 | Use `Array.prototype.reverse()` and `Array.prototype.findIndex()` to find the appropriate last index where the element should be inserted, based on the provided iterator function. 1679 | 1680 | ```js 1681 | const sortedLastIndexBy = (arr, n, fn) => { 1682 | const isDescending = fn(arr[0]) > fn(arr[arr.length - 1]); 1683 | const val = fn(n); 1684 | const index = arr 1685 | .map(fn) 1686 | .reverse() 1687 | .findIndex(el => (isDescending ? val <= el : val >= el)); 1688 | return index === -1 ? 0 : arr.length - index; 1689 | }; 1690 | ``` 1691 | 1692 | 1693 | 示例 1694 | 1695 | ```js 1696 | sortedLastIndexBy([{ x: 4 }, { x: 5 }], { x: 4 }, o => o.x); // 1 1697 | ``` 1698 | 1699 | 1700 | 1701 | 1702 | 1703 | ### stableSort ![advanced](/advanced.svg) 1704 | 1705 | Performs stable sorting of an array, preserving the initial indexes of items when their values are the same. 1706 | Does not mutate the original array, but returns a new array instead. 1707 | 1708 | Use `Array.prototype.map()` to pair each element of the input array with its corresponding index. 1709 | Use `Array.prototype.sort()` and a `compare` function to sort the list, preserving their initial order if the items compared are equal. 1710 | Use `Array.prototype.map()` to convert back to the initial array items. 1711 | 1712 | ```js 1713 | const stableSort = (arr, compare) => 1714 | arr 1715 | .map((item, index) => ({ item, index })) 1716 | .sort((a, b) => compare(a.item, b.item) || a.index - b.index) 1717 | .map(({ item }) => item); 1718 | ``` 1719 | 1720 | 1721 | 示例 1722 | 1723 | ```js 1724 | const arr = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; 1725 | const stable = stableSort(arr, () => 0); // [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10] 1726 | ``` 1727 | 1728 | 1729 | 1730 | 1731 | 1732 | ### symmetricDifference 1733 | 1734 | Returns the symmetric difference between two arrays, without filtering out duplicate values. 1735 | 1736 | Create a `Set` from each array, then use `Array.prototype.filter()` on each of them to only keep values not contained in the other. 1737 | 1738 | ```js 1739 | const symmetricDifference = (a, b) => { 1740 | const sA = new Set(a), 1741 | sB = new Set(b); 1742 | return [...a.filter(x => !sB.has(x)), ...b.filter(x => !sA.has(x))]; 1743 | }; 1744 | ``` 1745 | 1746 | 1747 | 示例 1748 | 1749 | ```js 1750 | symmetricDifference([1, 2, 3], [1, 2, 4]); // [3, 4] 1751 | symmetricDifference([1, 2, 2], [1, 3, 1]); // [2, 2, 3] 1752 | ``` 1753 | 1754 | 1755 | 1756 | 1757 | 1758 | ### symmetricDifferenceBy 1759 | 1760 | Returns the symmetric difference between two arrays, after applying the provided function to each array element of both. 1761 | 1762 | Create a `Set` by applying `fn` to each array's elements, then use `Array.prototype.filter()` on each of them to only keep values not contained in the other. 1763 | 1764 | ```js 1765 | const symmetricDifferenceBy = (a, b, fn) => { 1766 | const sA = new Set(a.map(v => fn(v))), 1767 | sB = new Set(b.map(v => fn(v))); 1768 | return [...a.filter(x => !sB.has(fn(x))), ...b.filter(x => !sA.has(fn(x)))]; 1769 | }; 1770 | ``` 1771 | 1772 | 1773 | 示例 1774 | 1775 | ```js 1776 | symmetricDifferenceBy([2.1, 1.2], [2.3, 3.4], Math.floor); // [ 1.2, 3.4 ] 1777 | ``` 1778 | 1779 | 1780 | 1781 | 1782 | 1783 | ### symmetricDifferenceWith 1784 | 1785 | Returns the symmetric difference between two arrays, using a provided function as a comparator. 1786 | 1787 | Use `Array.prototype.filter()` and `Array.prototype.findIndex()` to find the appropriate values. 1788 | 1789 | ```js 1790 | const symmetricDifferenceWith = (arr, val, comp) => [ 1791 | ...arr.filter(a => val.findIndex(b => comp(a, b)) === -1), 1792 | ...val.filter(a => arr.findIndex(b => comp(a, b)) === -1) 1793 | ]; 1794 | ``` 1795 | 1796 | 1797 | 示例 1798 | 1799 | ```js 1800 | symmetricDifferenceWith( 1801 | [1, 1.2, 1.5, 3, 0], 1802 | [1.9, 3, 0, 3.9], 1803 | (a, b) => Math.round(a) === Math.round(b) 1804 | ); // [1, 1.2, 3.9] 1805 | ``` 1806 | 1807 | 1808 | 1809 | 1810 | 1811 | ### tail 1812 | 1813 | Returns all elements in an array except for the first one. 1814 | 1815 | Return `Array.prototype.slice(1)` if the array's `length` is more than `1`, otherwise, return the whole array. 1816 | 1817 | ```js 1818 | const tail = arr => (arr.length > 1 ? arr.slice(1) : arr); 1819 | ``` 1820 | 1821 | 1822 | 示例 1823 | 1824 | ```js 1825 | tail([1, 2, 3]); // [2,3] 1826 | tail([1]); // [1] 1827 | ``` 1828 | 1829 | 1830 | 1831 | 1832 | 1833 | ### take 1834 | 1835 | Returns an array with n elements removed from the beginning. 1836 | 1837 | Use `Array.prototype.slice()` to create a slice of the array with `n` elements taken from the beginning. 1838 | 1839 | ```js 1840 | const take = (arr, n = 1) => arr.slice(0, n); 1841 | ``` 1842 | 1843 | 1844 | 示例 1845 | 1846 | ```js 1847 | take([1, 2, 3], 5); // [1, 2, 3] 1848 | take([1, 2, 3], 0); // [] 1849 | ``` 1850 | 1851 | 1852 | 1853 | 1854 | 1855 | ### takeRight 1856 | 1857 | Returns an array with n elements removed from the end. 1858 | 1859 | Use `Array.prototype.slice()` to create a slice of the array with `n` elements taken from the end. 1860 | 1861 | ```js 1862 | const takeRight = (arr, n = 1) => arr.slice(arr.length - n, arr.length); 1863 | ``` 1864 | 1865 | 1866 | 示例 1867 | 1868 | ```js 1869 | takeRight([1, 2, 3], 2); // [ 2, 3 ] 1870 | takeRight([1, 2, 3]); // [3] 1871 | ``` 1872 | 1873 | 1874 | 1875 | 1876 | 1877 | ### takeRightWhile 1878 | 1879 | Removes elements from the end of an array until the passed function returns `true`. Returns the removed elements. 1880 | 1881 | Loop through the array, using a `Array.prototype.reduceRight()` and accumulating elements while the function returns falsy value. 1882 | 1883 | ```js 1884 | const takeRightWhile = (arr, func) => 1885 | arr.reduceRight((acc, el) => (func(el) ? acc : [el, ...acc]), []); 1886 | ``` 1887 | 1888 | 1889 | 示例 1890 | 1891 | ```js 1892 | takeRightWhile([1, 2, 3, 4], n => n < 3); // [3, 4] 1893 | ``` 1894 | 1895 | 1896 | 1897 | 1898 | 1899 | ### takeWhile 1900 | 1901 | Removes elements in an array until the passed function returns `true`. Returns the removed elements. 1902 | 1903 | Loop through the array, using a `for...of` loop over `Array.prototype.entries()` until the returned value from the function is `true`. 1904 | Return the removed elements, using `Array.prototype.slice()`. 1905 | 1906 | ```js 1907 | const takeWhile = (arr, func) => { 1908 | for (const [i, val] of arr.entries()) if (func(val)) return arr.slice(0, i); 1909 | return arr; 1910 | }; 1911 | ``` 1912 | 1913 | 1914 | 示例 1915 | 1916 | ```js 1917 | takeWhile([1, 2, 3, 4], n => n >= 3); // [1, 2] 1918 | ``` 1919 | 1920 | 1921 | 1922 | 1923 | 1924 | ### toHash 1925 | 1926 | Reduces a given Array-like into a value hash (keyed data store). 1927 | 1928 | Given an Iterable or Array-like structure, call `Array.prototype.reduce.call()` on the provided object to step over it and return an Object, keyed by the reference value. 1929 | 1930 | ```js 1931 | const toHash = (object, key) => 1932 | Array.prototype.reduce.call( 1933 | object, 1934 | (acc, data, index) => ((acc[!key ? index : data[key]] = data), acc), 1935 | {} 1936 | ); 1937 | ``` 1938 | 1939 | 1940 | 示例 1941 | 1942 | ```js 1943 | toHash([4, 3, 2, 1]); // { 0: 4, 1: 3, 2: 2, 3: 1 } 1944 | toHash([{ a: 'label' }], 'a'); // { label: { a: 'label' } } 1945 | // A more in depth example: 1946 | let users = [{ id: 1, first: 'Jon' }, { id: 2, first: 'Joe' }, { id: 3, first: 'Moe' }]; 1947 | let managers = [{ manager: 1, employees: [2, 3] }]; 1948 | // We use function here because we want a bindable reference, but a closure referencing the hash would work, too. 1949 | managers.forEach( 1950 | manager => 1951 | (manager.employees = manager.employees.map(function(id) { 1952 | return this[id]; 1953 | }, toHash(users, 'id'))) 1954 | ); 1955 | managers; // [ { manager:1, employees: [ { id: 2, first: "Joe" }, { id: 3, first: "Moe" } ] } ] 1956 | ``` 1957 | 1958 | 1959 | 1960 | 1961 | 1962 | ### union 1963 | 1964 | Returns every element that exists in any of the two arrays once. 1965 | 1966 | Create a `Set` with all values of `a` and `b` and convert to an array. 1967 | 1968 | ```js 1969 | const union = (a, b) => Array.from(new Set([...a, ...b])); 1970 | ``` 1971 | 1972 | 1973 | 示例 1974 | 1975 | ```js 1976 | union([1, 2, 3], [4, 3, 2]); // [1,2,3,4] 1977 | ``` 1978 | 1979 | 1980 | 1981 | 1982 | 1983 | ### unionBy 1984 | 1985 | Returns every element that exists in any of the two arrays once, after applying the provided function to each array element of both. 1986 | 1987 | Create a `Set` by applying all `fn` to all values of `a`. 1988 | Create a `Set` from `a` and all elements in `b` whose value, after applying `fn` does not match a value in the previously created set. 1989 | Return the last set converted to an array. 1990 | 1991 | ```js 1992 | const unionBy = (a, b, fn) => { 1993 | const s = new Set(a.map(fn)); 1994 | return Array.from(new Set([...a, ...b.filter(x => !s.has(fn(x)))])); 1995 | }; 1996 | ``` 1997 | 1998 | 1999 | 示例 2000 | 2001 | ```js 2002 | unionBy([2.1], [1.2, 2.3], Math.floor); // [2.1, 1.2] 2003 | ``` 2004 | 2005 | 2006 | 2007 | 2008 | 2009 | ### unionWith 2010 | 2011 | Returns every element that exists in any of the two arrays once, using a provided comparator function. 2012 | 2013 | Create a `Set` with all values of `a` and values in `b` for which the comparator finds no matches in `a`, using `Array.prototype.findIndex()`. 2014 | 2015 | ```js 2016 | const unionWith = (a, b, comp) => 2017 | Array.from(new Set([...a, ...b.filter(x => a.findIndex(y => comp(x, y)) === -1)])); 2018 | ``` 2019 | 2020 | 2021 | 示例 2022 | 2023 | ```js 2024 | unionWith([1, 1.2, 1.5, 3, 0], [1.9, 3, 0, 3.9], (a, b) => Math.round(a) === Math.round(b)); // [1, 1.2, 1.5, 3, 0, 3.9] 2025 | ``` 2026 | 2027 | 2028 | 2029 | 2030 | 2031 | ### uniqueElements 2032 | 2033 | Returns all unique values of an array. 2034 | 2035 | Use ES6 `Set` and the `...rest` operator to discard all duplicated values. 2036 | 2037 | ```js 2038 | const uniqueElements = arr => [...new Set(arr)]; 2039 | ``` 2040 | 2041 | 2042 | 示例 2043 | 2044 | ```js 2045 | uniqueElements([1, 2, 2, 3, 4, 4, 5]); // [1, 2, 3, 4, 5] 2046 | ``` 2047 | 2048 | 2049 | 2050 | 2051 | 2052 | ### uniqueElementsBy 2053 | 2054 | Returns all unique values of an array, based on a provided comparator function. 2055 | 2056 | Use `Array.prototype.reduce()` and `Array.prototype.some()` for an array containing only the first unique occurence of each value, based on the comparator function, `fn`. 2057 | The comparator function takes two arguments: the values of the two elements being compared. 2058 | 2059 | ```js 2060 | const uniqueElementsBy = (arr, fn) => 2061 | arr.reduce((acc, v) => { 2062 | if (!acc.some(x => fn(v, x))) acc.push(v); 2063 | return acc; 2064 | }, []); 2065 | ``` 2066 | 2067 | 2068 | 示例 2069 | 2070 | ```js 2071 | uniqueElementsBy( 2072 | [ 2073 | { id: 0, value: 'a' }, 2074 | { id: 1, value: 'b' }, 2075 | { id: 2, value: 'c' }, 2076 | { id: 1, value: 'd' }, 2077 | { id: 0, value: 'e' } 2078 | ], 2079 | (a, b) => a.id == b.id 2080 | ); // [ { id: 0, value: 'a' }, { id: 1, value: 'b' }, { id: 2, value: 'c' } ] 2081 | ``` 2082 | 2083 | 2084 | 2085 | 2086 | 2087 | ### uniqueElementsByRight 2088 | 2089 | Returns all unique values of an array, based on a provided comparator function. 2090 | 2091 | Use `Array.prototype.reduce()` and `Array.prototype.some()` for an array containing only the last unique occurence of each value, based on the comparator function, `fn`. 2092 | The comparator function takes two arguments: the values of the two elements being compared. 2093 | 2094 | ```js 2095 | const uniqueElementsByRight = (arr, fn) => 2096 | arr.reduceRight((acc, v) => { 2097 | if (!acc.some(x => fn(v, x))) acc.push(v); 2098 | return acc; 2099 | }, []); 2100 | ``` 2101 | 2102 | 2103 | 示例 2104 | 2105 | ```js 2106 | uniqueElementsByRight( 2107 | [ 2108 | { id: 0, value: 'a' }, 2109 | { id: 1, value: 'b' }, 2110 | { id: 2, value: 'c' }, 2111 | { id: 1, value: 'd' }, 2112 | { id: 0, value: 'e' } 2113 | ], 2114 | (a, b) => a.id == b.id 2115 | ); // [ { id: 0, value: 'e' }, { id: 1, value: 'd' }, { id: 2, value: 'c' } ] 2116 | ``` 2117 | 2118 | 2119 | 2120 | 2121 | 2122 | ### uniqueSymmetricDifference 2123 | 2124 | Returns the unique symmetric difference between two arrays, not containing duplicate values from either array. 2125 | 2126 | Use `Array.prototype.filter()` and `Array.prototype.includes()` on each array to remove values contained in the other, then create a `Set` from the results, removing duplicate values. 2127 | 2128 | ```js 2129 | const uniqueSymmetricDifference = (a, b) => [ 2130 | ...new Set([...a.filter(v => !b.includes(v)), ...b.filter(v => !a.includes(v))]) 2131 | ]; 2132 | ``` 2133 | 2134 | 2135 | 示例 2136 | 2137 | ```js 2138 | uniqueSymmetricDifference([1, 2, 3], [1, 2, 4]); // [3, 4] 2139 | uniqueSymmetricDifference([1, 2, 2], [1, 3, 1]); // [2, 3] 2140 | ``` 2141 | 2142 | 2143 | 2144 | 2145 | 2146 | ### unzip 2147 | 2148 | Creates an array of arrays, ungrouping the elements in an array produced by [zip](#zip). 2149 | 2150 | Use `Math.max.apply()` to get the longest subarray in the array, `Array.prototype.map()` to make each element an array. 2151 | Use `Array.prototype.reduce()` and `Array.prototype.forEach()` to map grouped values to individual arrays. 2152 | 2153 | ```js 2154 | const unzip = arr => 2155 | arr.reduce( 2156 | (acc, val) => (val.forEach((v, i) => acc[i].push(v)), acc), 2157 | Array.from({ 2158 | length: Math.max(...arr.map(x => x.length)) 2159 | }).map(x => []) 2160 | ); 2161 | ``` 2162 | 2163 | 2164 | 示例 2165 | 2166 | ```js 2167 | unzip([['a', 1, true], ['b', 2, false]]); // [['a', 'b'], [1, 2], [true, false]] 2168 | unzip([['a', 1, true], ['b', 2]]); // [['a', 'b'], [1, 2], [true]] 2169 | ``` 2170 | 2171 | 2172 | 2173 | 2174 | 2175 | ### unzipWith ![advanced](/advanced.svg) 2176 | 2177 | Creates an array of elements, ungrouping the elements in an array produced by [zip](#zip) and applying the provided function. 2178 | 2179 | Use `Math.max.apply()` to get the longest subarray in the array, `Array.prototype.map()` to make each element an array. 2180 | Use `Array.prototype.reduce()` and `Array.prototype.forEach()` to map grouped values to individual arrays. 2181 | Use `Array.prototype.map()` and the spread operator (`...`) to apply `fn` to each individual group of elements. 2182 | 2183 | ```js 2184 | const unzipWith = (arr, fn) => 2185 | arr 2186 | .reduce( 2187 | (acc, val) => (val.forEach((v, i) => acc[i].push(v)), acc), 2188 | Array.from({ 2189 | length: Math.max(...arr.map(x => x.length)) 2190 | }).map(x => []) 2191 | ) 2192 | .map(val => fn(...val)); 2193 | ``` 2194 | 2195 | 2196 | 示例 2197 | 2198 | ```js 2199 | unzipWith([[1, 10, 100], [2, 20, 200]], (...args) => args.reduce((acc, v) => acc + v, 0)); // [3, 30, 300] 2200 | ``` 2201 | 2202 | 2203 | 2204 | 2205 | 2206 | ### without 2207 | 2208 | Filters out the elements of an array, that have one of the specified values. 2209 | 2210 | Use `Array.prototype.filter()` to create an array excluding(using `!Array.includes()`) all given values. 2211 | 2212 | _(For a snippet that mutates the original array see [`pull`](#pull))_ 2213 | 2214 | ```js 2215 | const without = (arr, ...args) => arr.filter(v => !args.includes(v)); 2216 | ``` 2217 | 2218 | 2219 | 示例 2220 | 2221 | ```js 2222 | without([2, 1, 2, 3], 1, 2); // [3] 2223 | ``` 2224 | 2225 | 2226 | 2227 | 2228 | 2229 | ### xProd 2230 | 2231 | Creates a new array out of the two supplied by creating each possible pair from the arrays. 2232 | 2233 | Use `Array.prototype.reduce()`, `Array.prototype.map()` and `Array.prototype.concat()` to produce every possible pair from the elements of the two arrays and save them in an array. 2234 | 2235 | ```js 2236 | const xProd = (a, b) => a.reduce((acc, x) => acc.concat(b.map(y => [x, y])), []); 2237 | ``` 2238 | 2239 | 2240 | 示例 2241 | 2242 | ```js 2243 | xProd([1, 2], ['a', 'b']); // [[1, 'a'], [1, 'b'], [2, 'a'], [2, 'b']] 2244 | ``` 2245 | 2246 | 2247 | 2248 | 2249 | 2250 | ### zip 2251 | 2252 | Creates an array of elements, grouped based on the position in the original arrays. 2253 | 2254 | Use `Math.max.apply()` to get the longest array in the arguments. 2255 | Creates an array with that length as return value and use `Array.from()` with a map-function to create an array of grouped elements. 2256 | If lengths of the argument-arrays vary, `undefined` is used where no value could be found. 2257 | 2258 | ```js 2259 | const zip = (...arrays) => { 2260 | const maxLength = Math.max(...arrays.map(x => x.length)); 2261 | return Array.from({ length: maxLength }).map((_, i) => { 2262 | return Array.from({ length: arrays.length }, (_, k) => arrays[k][i]); 2263 | }); 2264 | }; 2265 | ``` 2266 | 2267 | 2268 | 示例 2269 | 2270 | ```js 2271 | zip(['a', 'b'], [1, 2], [true, false]); // [['a', 1, true], ['b', 2, false]] 2272 | zip(['a'], [1, 2], [true, false]); // [['a', 1, true], [undefined, 2, false]] 2273 | ``` 2274 | 2275 | 2276 | 2277 | 2278 | 2279 | ### zipObject 2280 | 2281 | Given an array of valid property identifiers and an array of values, return an object associating the properties to the values. 2282 | 2283 | Since an object can have undefined values but not undefined property pointers, the array of properties is used to decide the structure of the resulting object using `Array.prototype.reduce()`. 2284 | 2285 | ```js 2286 | const zipObject = (props, values) => 2287 | props.reduce((obj, prop, index) => ((obj[prop] = values[index]), obj), {}); 2288 | ``` 2289 | 2290 | 2291 | 示例 2292 | 2293 | ```js 2294 | zipObject(['a', 'b', 'c'], [1, 2]); // {a: 1, b: 2, c: undefined} 2295 | zipObject(['a', 'b'], [1, 2, 3]); // {a: 1, b: 2} 2296 | ``` 2297 | 2298 | 2299 | 2300 | 2301 | 2302 | ### zipWith ![advanced](/advanced.svg) 2303 | 2304 | Creates an array of elements, grouped based on the position in the original arrays and using function as the last value to specify how grouped values should be combined. 2305 | 2306 | Check if the last argument provided is a function. 2307 | Use `Math.max()` to get the longest array in the arguments. 2308 | Creates an array with that length as return value and use `Array.from()` with a map-function to create an array of grouped elements. 2309 | If lengths of the argument-arrays vary, `undefined` is used where no value could be found. 2310 | The function is invoked with the elements of each group `(...group)`. 2311 | 2312 | ```js 2313 | const zipWith = (...array) => { 2314 | const fn = typeof array[array.length - 1] === 'function' ? array.pop() : undefined; 2315 | return Array.from( 2316 | { length: Math.max(...array.map(a => a.length)) }, 2317 | (_, i) => (fn ? fn(...array.map(a => a[i])) : array.map(a => a[i])) 2318 | ); 2319 | }; 2320 | ``` 2321 | 2322 | 2323 | 示例 2324 | 2325 | ```js 2326 | zipWith([1, 2], [10, 20], [100, 200], (a, b, c) => a + b + c); // [111,222] 2327 | zipWith( 2328 | [1, 2, 3], 2329 | [10, 20], 2330 | [100, 200], 2331 | (a, b, c) => (a != null ? a : 'a') + (b != null ? b : 'b') + (c != null ? c : 'c') 2332 | ); // [111, 222, '3bc'] 2333 | ``` 2334 | 2335 | 2336 | 2337 | 2338 | --------------------------------------------------------------------------------