Array
all
如果提供的断言函数(predicate function)对集合中所有的元素测试都返回 true
,那么 all
方法就返回 true
。否则,返回 false
。
使用 Array.prototype.every()
测试集合中的所有元素是否基于 fn
返回 true
。 省略第二个参数fn
,使用 Boolean
作为默认值。
const all = (arr, fn = Boolean) => arr.every(fn);
all([4, 2, 3], x => x > 1); // true all([1, 2, 3]); // true
allEqual
检查数组中的所有元素是否相等。
使用 Array.prototype.every()
检查数组中的所有元素是否与第一个元素相同。 使用严格比较运算符比较数组中的元素,该运算符不考虑 NaN
与自己不相等的情况。
const allEqual = arr => arr.every(val => val === arr[0]);
allEqual([1, 2, 3, 4, 5, 6]); // false allEqual([1, 1, 1, 1]); // true
any
如果提供的断言函数(predicate function)对集合中所有的元素测试,至少有一个返回 true
,那么 any
方法就返回 true
。否则,返回 false
。
使用 Array.prototype.some()
测试集合中的所有元素是否基于 fn
返回 true
。 省略第二个参数fn
,使用 Boolean
作为默认值。
const any = (arr, fn = Boolean) => arr.some(fn);
any([0, 1, 2, 0], x => x >= 2); // true any([0, 0, 1, 0]); // true
arrayToCSV
将二维数组转换为逗号分隔值(CSV)字符串。
使用 Array.prototype.map()
和 Array.prototype.join(delimiter)
将单个一维数组(行)组合成字符串。 使用 Array.prototype.join('\n')
将所有行组合成 CSV 字符串,用换行符分隔每一行。 省略第二个参数 delimiter
,以使用','的默认分隔符。
const arrayToCSV = (arr, delimiter = ',') => arr .map(v => v.map(x => (isNaN(x) ? `"${x.replace(/"/g, '""')}"` : x)).join(delimiter)) .join('\n');
arrayToCSV([['a', 'b'], ['c', 'd']]); // '"a","b"\n"c","d"' arrayToCSV([['a', 'b'], ['c', 'd']], ';'); // '"a";"b"\n"c";"d"' arrayToCSV([['a', '"b" great'], ['c', 3.1415]]); // '"a","""b"" great"\n"c",3.1415'
bifurcate
将值分成两组,如果 filter
中的元素为 true
,则集合中对应的元素属于第一组;否则,它属于第二组。
基于 filter
,使用 Array.prototype.reduce()
和 Array.prototype.push()
向组添加元素。
const bifurcate = (arr, filter) => arr.reduce((acc, val, i) => (acc[filter[i] ? 0 : 1].push(val), acc), [[], []]);
bifurcate(['beep', 'boop', 'foo', 'bar'], [true, true, false, true]); // [ ['beep', 'boop', 'bar'], ['foo'] ]
bifurcateBy
根据断言函数(predicate function)会将值分成两组,集合中的元素输入到断言函数中后,来确定元素属于哪一组。如果断言函数返回一个真值,则集合元素属于第一组;否则,它属于第二组。
const bifurcateBy = (arr, fn) => arr.reduce((acc, val, i) => (acc[fn(val, i) ? 0 : 1].push(val), acc), [[], []]);
bifurcateBy(['beep', 'boop', 'foo', 'bar'], x => x[0] === 'b'); // [ ['beep', 'boop', 'bar'], ['foo'] ]
chunk
将数组分块成指定大小的较小数组。
使用 array.from()
创建一个新的数组,该数组的长度就是将要生成的块(chunk)的个数。 使用 array.prototype.slice()
将新数组的每个元素映射为一个长度为 size
的块(chunk)。 如果原始数组不能被平均分割,那么最后的块(chunk)将包含剩余的元素。
const chunk = (arr, size) => Array.from({ length: Math.ceil(arr.length / size) }, (v, i) => arr.slice(i * size, i * size + size) );
chunk([1, 2, 3, 4, 5], 2); // [[1,2],[3,4],[5]]
compact
从数组中删除为 false
的值。
使用 Array.prototype.filter()
过滤掉数组中所有为假值的元素 (false
, null
, 0
, ""
, undefined
, 和 NaN
)。
const compact = arr => arr.filter(Boolean);
compact([0, 1, false, 2, '', 3, 'a', 'e' * 23, NaN, 's', 34]); // [ 1, 2, 3, 'a', 's', 34 ]
countBy
根据给定函数对数组的元素进行分组,并返回每个组中的元素数量。
使用 array .prototype.map()
将数组的值映射到函数或属性名称。 使用 Array.prototype.reduce()
创建一个对象,其中键(key
)是从映射的结果中产生的。
const countBy = (arr, fn) => arr.map(typeof fn === 'function' ? fn : val => val[fn]).reduce((acc, val) => { acc[val] = (acc[val] || 0) + 1; return acc; }, {});
countBy([6.1, 4.2, 6.3], Math.floor); // {4: 1, 6: 2} countBy(['one', 'two', 'three'], 'length'); // {3: 2, 5: 1}
countOccurrences
计算数组中值的出现次数。
每次在数组中遇到指定的值时,使用 array. prototype.reduce()
递增计数器。
const countOccurrences = (arr, val) => arr.reduce((a, v) => (v === val ? a + 1 : a), 0);
countOccurrences([1, 1, 2, 1, 2, 3], 1); // 3
deepFlatten
深度平铺一个数组。
使用递归。 使用 array. prototype.concat()
和空数组( []
),结合 spread 操作符('...')将数组平铺。 递归平铺数组中的每个元素。
const deepFlatten = arr => [].concat(...arr.map(v => (Array.isArray(v) ? deepFlatten(v) : v)));
deepFlatten([1, [2], [[3], 4], 5]); // [1,2,3,4,5]
difference
返回两个数组之间的差异。
根据数组 b
创建一个 Set
对象,然后在数组 a
上使用 Array.filter()
方法,过滤出数组 b
中不包含的值。
const difference = (a, b) => { const s = new Set(b); return a.filter(x => !s.has(x)); };
difference([1, 2, 3], [1, 2, 4]); // [3]
differenceBy
将提供的函数应用于两个数组的每个数组元素后,返回两个数组之间的差值。
将 fn
处理数组 b
中的每个元素后创建 Set
,然后使用 Array.prototype.map()
映射 fn
处理数组 a
中的每个元素,最后应用Array.prototype.filter()
进行过滤。
const differenceBy = (a, b, fn) => { const s = new Set(b.map(fn)); return a.map(fn).filter(el => !s.has(el)); };
differenceBy([2.1, 1.2], [2.3, 3.4], Math.floor); // [1] differenceBy([{ x: 2 }, { x: 1 }], [{ x: 1 }], v => v.x); // [2]
differenceWith
过滤出数组中比较函数不返回 true
的所有值。
使用 Array.prototype.filter()
和 Array.prototype.findIndex()
查找合适的值。
const differenceWith = (arr, val, comp) => arr.filter(a => val.findIndex(b => comp(a, b)) === -1);
differenceWith([1, 1.2, 1.5, 3, 0], [1.9, 3, 0], (a, b) => Math.round(a) === Math.round(b)); // [1, 1.2]
drop
返回从左侧开始删除 n
个元素的新数组。
使用 Array.prototype.slice()
从左边删除指定数量的元素。
const drop = (arr, n = 1) => arr.slice(n);
drop([1, 2, 3]); // [2,3] drop([1, 2, 3], 2); // [3] drop([1, 2, 3], 42); // []
dropRight
返回从右侧开始删除 n
个元素的新数组。
使用 Array.prototype.slice()
从右侧删除指定数量的元素。
const dropRight = (arr, n = 1) => arr.slice(0, -n);
dropRight([1, 2, 3]); // [1,2] dropRight([1, 2, 3], 2); // [1] dropRight([1, 2, 3], 42); // []
dropRightWhile
从数组末尾移除元素,直到传递的函数返回 true
。返回数组中剩余的元素。
从数组的末尾开始循环遍历数组,使用 array.prototype.slice()
删除数组中第一个遇到函数返回的值为 true
位置的元素。 返回数组中剩余的元素。
const dropRightWhile = (arr, func) => { let rightIndex = arr.length; while (rightIndex-- && !func(arr[rightIndex])); return arr.slice(0, rightIndex + 1); };
dropRightWhile([1, 2, 3, 4], n => n < 3); // [1, 2]
dropWhile
移除数组中的元素,直到传递的函数返回 true
。 返回数组中剩余的元素。
循环遍历数组,使用 array.prototype.slice()
删除数组中第一个遇到函数返回的值为 true
位置的元素。 返回数组中剩余的元素。
const dropWhile = (arr, func) => { while (arr.length > 0 && !func(arr[0])) arr = arr.slice(1); return arr; };
dropWhile([1, 2, 3, 4], n => n >= 3); // [3,4]
everyNth
Returns every nth element in an array.
Use Array.prototype.filter()
to create a new array that contains every nth element of a given array.
const everyNth = (arr, nth) => arr.filter((e, i) => i % nth === nth - 1);
everyNth([1, 2, 3, 4, 5, 6], 2); // [ 2, 4, 6 ]
filterFalsy
Filters out the falsy values in an array.
Use Array.prototype.filter()
to get an array containing only truthy values.
过滤数组中为假值(falsy)的元素。
使用 array .prototype.filter()
过滤后,数组中只包含为真值(truthy)的元素。
const filterFalsy = arr => arr.filter(Boolean);
filterFalsy(['', true, {}, false, 'sample', 1, 0]); // [true, {}, 'sample', 1]
filterNonUnique
过滤掉数组中的非唯一值。
使用 Array.prototype.filter()
过滤非唯一值后,返回只包含唯一值的数组。
const filterNonUnique = arr => arr.filter(i => arr.indexOf(i) === arr.lastIndexOf(i));
filterNonUnique([1, 2, 2, 3, 4, 4, 5]); // [1, 3, 5]
filterNonUniqueBy
根据提供的比较器(comparator)函数,过滤数组中的非唯一值。
基于比较器函数 fn
,使用 array .prototype.filter()
和 array .prototype.every()
对数组过滤后,数组中只包含唯一值。
比较器函数接受四个参数:正在比较的两个元素的值及其索引。
const filterNonUniqueBy = (arr, fn) => arr.filter((v, i) => arr.every((x, j) => (i === j) === fn(v, x, i, j)));
filterNonUniqueBy( [ { id: 0, value: 'a' }, { id: 1, value: 'b' }, { id: 2, value: 'c' }, { id: 1, value: 'd' }, { id: 0, value: 'e' } ], (a, b) => a.id == b.id ); // [ { id: 2, value: 'c' } ]
findLast
通过提供的函数返回值为真值(truthy)过滤数组,返回这个数组最后一个元素。
使用 Array.prototype.filter()
过滤掉 fn
返回假值(falsy)的元素, 用 Array.prototype.pop()
获取最后一个值。
const findLast = (arr, fn) => arr.filter(fn).pop();
findLast([1, 2, 3, 4], n => n % 2 === 1); // 3
findLastIndex
通过提供的函数返回值为真值(truthy)过滤数组,返回这个数组最后一个元素的下标。
使用 array.prototype.map()
将每个元素映射到具有其索引和值的数组。 使用 Array.prototype.filter()
过滤掉 fn
返回假值(falsy)的元素, 用 Array.prototype.pop()
获取最后一个值。
const findLastIndex = (arr, fn) => arr .map((val, i) => [i, val]) .filter(([i, val]) => fn(val, i, arr)) .pop()[0];
findLastIndex([1, 2, 3, 4], n => n % 2 === 1); // 2 (index of the value 3)
flatten
将数组展平到指定的深度。
使用递归,为每个深度级别 depth
递减 1
。 使用 Array.prototype.reduce()
和 Array.prototype.concat()
来合并元素或数组。 基本情况下,depth
等于 1
停止递归。 省略第二个参数,depth
只能平铺到 1
层(单层平铺) 的深度。
const flatten = (arr, depth = 1) => arr.reduce((a, v) => a.concat(depth > 1 && Array.isArray(v) ? flatten(v, depth - 1) : v), []);
flatten([1, [2], 3, 4]); // [1, 2, 3, 4] flatten([1, [2, [3, [4, 5], 6], 7], 8], 2); // [1, 2, 3, [4, 5], 6, 7, 8]
forEachRight
从数组的最后一个元素开始,为每个数组元素执行一次提供的函数。
使用 Array.prototype.slice(0)
克隆给定的数组,Array.prototype.reverse()
反转数组,Array.prototype.forEach()
遍历这个反转的数组。
const forEachRight = (arr, callback) => arr .slice(0) .reverse() .forEach(callback);
forEachRight([1, 2, 3, 4], val => console.log(val)); // '4', '3', '2', '1'
groupBy
根据给定的函数对数组的元素进行分组。
使用 Array.prototype.map()
将数组的值映射到函数或属性名称。使用 Array.prototype.reduce()
来创建一个对象,其中的 key
是从映射结果中产生。
const groupBy = (arr, fn) => arr.map(typeof fn === 'function' ? fn : val => val[fn]).reduce((acc, val, i) => { acc[val] = (acc[val] || []).concat(arr[i]); return acc; }, {});
groupBy([6.1, 4.2, 6.3], Math.floor); // {4: [4.2], 6: [6.1, 6.3]} groupBy(['one', 'two', 'three'], 'length'); // {3: ['one', 'two'], 5: ['three']}
head
返回数组的第一个元素。
使用 arr[0]
返回传递数组的第一个元素。
const head = arr => arr[0];
head([1, 2, 3]); // 1
indexOfAll
返回数组中 val
的所有索引。如果在数组中没找到 val
,则返回 []
。
使用 Array.prototype.reduce()
循环元素并存储匹配元素的索引。 返回索引数组。
const indexOfAll = (arr, val) => arr.reduce((acc, el, i) => (el === val ? [...acc, i] : acc), []);
indexOfAll([1, 2, 3, 1, 2, 3], 1); // [0,3] indexOfAll([1, 2, 3], 4); // []
initial
返回数组中除最后一个元素外的所有元素。
使用 arr.slice(0,-1)
返回数组中除最后一个元素外的所有元素。
const initial = arr => arr.slice(0, -1);
initial([1, 2, 3]); // [1,2]
initialize2DArray
初始化一个给定行数和列数,以及值的二维数组。
使用 array.prototype.map()
生成 h
行,其中每一行都是长度为 w
的新数组。如果没有提供值 val
,则默认为 null
。
const initialize2DArray = (w, h, val = null) => Array.from({ length: h }).map(() => Array.from({ length: w }).fill(val));
initialize2DArray(2, 2, 0); // [[0,0], [0,0]]
initializeArrayWithRange
初始化一个数组,该数组包含指定范围 start
到 end
内的数字,可设置间隔 step
。
使用 Array.from()
创建一个所需长度为 (end - start + 1)/step
的数组,并填充给定范围内要求的值。 你可以省略 start
来使用默认值 0
。 你可以省略 step
使用默认值 1
。
const initializeArrayWithRange = (end, start = 0, step = 1) => Array.from({ length: Math.ceil((end - start + 1) / step) }, (v, i) => i * step + start);
initializeArrayWithRange(5); // [0,1,2,3,4,5] initializeArrayWithRange(7, 3); // [3,4,5,6,7] initializeArrayWithRange(9, 0, 2); // [0,2,4,6,8]
initializeArrayWithRangeRight
[待翻译]
初始化一个数组,该数组包含指定范围 start
到 end
内的数字(反向),可设置间隔 step
。
使用 array.from(Math.ceil((end+1-start)/step)
来创建所需长度的数组(元素的数量等于 (end-start)/step
或 (end+1-start)/step
,包含结束数字), 使用 array.prototype.map()
来填充范围中所需要的值。
const initializeArrayWithRangeRight = (end, start = 0, step = 1) => Array.from({ length: Math.ceil((end + 1 - start) / step) }).map( (v, i, arr) => (arr.length - i - 1) * step + start );
initializeArrayWithRangeRight(5); // [5,4,3,2,1,0] initializeArrayWithRangeRight(7, 3); // [7,6,5,4,3] initializeArrayWithRangeRight(9, 0, 2); // [8,6,4,2,0]
initializeArrayWithValues
使用指定的值初始化和填充数组。
使用 Array(n)
创建所需长度的数组,使用 fill(v)
填充所需的值。 你可以忽略 val
,使用默认值 0
。
const initializeArrayWithValues = (n, val = 0) => Array(n).fill(val);
initializeArrayWithValues(5, 2); // [2, 2, 2, 2, 2]
initializeNDArray
创建一个具有给定值的 n
维数组。
使用递归。 使用 array.prototype.map()
生成行,其中每个行都是使用 initializeNDArray
初始化的新数组。
const initializeNDArray = (val, ...args) => args.length === 0 ? val : Array.from({ length: args[0] }).map(() => initializeNDArray(val, ...args.slice(1)));
initializeNDArray(1, 3); // [1,1,1] initializeNDArray(5, 2, 2, 2); // [[[5,5],[5,5]],[[5,5],[5,5]]]
intersection
返回两个数组中都存在的元素列表。
根据数组 b
创建一个 Set
对象,然后在数组 a
上使用 Array.prototype.filter()
方法,只保留数组 b
中也包含的值。
const intersection = (a, b) => { const s = new Set(b); return a.filter(x => s.has(x)); };
intersection([1, 2, 3], [4, 3, 2]); // [2, 3]
intersectionBy
将提供的函数应用于两个数组的每个数组元素后,返回两个数组中存在的元素列表。
将 fn
应用于 b
中的所有元素来创建 Set
对象 ,然后在 a
上使用 Array.prototype.filter()
,只保留调用 fn
应用于每个元素后,同时在 b
中存在的元素。
const intersectionBy = (a, b, fn) => { const s = new Set(b.map(fn)); return a.filter(x => s.has(fn(x))); };
intersectionBy([2.1, 1.2], [2.3, 3.4], Math.floor); // [2.1]
intersectionWith
使用提供的比较器(comparator)函数,返回两个数组中存在的元素列表。
使用 Array.prototype.filter()
和 Array.prototype.findIndex()
结合比较器(comparator)函数来确定交叉值。
const intersectionWith = (a, b, comp) => a.filter(x => b.findIndex(y => comp(x, y)) !== -1);
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]
isSorted
如果数组按升序排序,返回 1
;如果按降序排序,返回 -1
;如果没有排序,返回 0
。
计算前两个元素的顺序 direction
。 使用 Object.entries()
对数组对象进行循环并对它们进行比较。 如果 direction
改变了,返回 0
;如果循环直到最后一个元素,direction
没有改变,则返回 direction
。
const isSorted = arr => { let direction = -(arr[0] - arr[1]); for (let [i, val] of arr.entries()) { direction = !direction ? -(arr[i - 1] - arr[i]) : direction; if (i === arr.length - 1) return !direction ? 0 : direction; else if ((val - arr[i + 1]) * direction > 0) return 0; } };
isSorted([0, 1, 2, 2]); // 1 isSorted([4, 3, 2]); // -1 isSorted([4, 3, 5]); // 0
join
将数组的所有元素拼接成一个字符串并返回此字符串。 使用分隔符和结束分隔符。
使用 Array.prototype.reduce()
将元素拼接成一个字符串。 省略第二个参数 separator
,则默认使用分隔符','。 省略第三个参数 end
,默认使用与 separator
相同的值。
const join = (arr, separator = ',', end = separator) => arr.reduce( (acc, val, i) => i === arr.length - 2 ? acc + val + end : i === arr.length - 1 ? acc + val : acc + val + separator, '' );
join(['pen', 'pineapple', 'apple', 'pen'], ',', '&'); // "pen,pineapple,apple&pen" join(['pen', 'pineapple', 'apple', 'pen'], ','); // "pen,pineapple,apple,pen" join(['pen', 'pineapple', 'apple', 'pen']); // "pen,pineapple,apple,pen"
JSONtoCSV
将对象数组转换为仅包含指定的 columns
的逗号分隔值(CSV)字符串。
使用 Array.prototype.join(delimiter)
结合 columns
中的所有名称以创建第一行。 使用 Array.prototype.map()
和 Array.prototype.reduce()
为每个对象创建一行映射到 columns
中的值,用空字符串替换不存在的值。 使用 Array.prototype.join('\n')
将所有行组合成一个字符串。 省略第三个参数 delimiter
,使用 ,
为默认的分隔符。
const JSONtoCSV = (arr, columns, delimiter = ',') => [ columns.join(delimiter), ...arr.map(obj => columns.reduce( (acc, key) => `${acc}${!acc.length ? '' : delimiter}"${!obj[key] ? '' : obj[key]}"`, '' ) ) ].join('\n');
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"' 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"'
last
返回数组中的最后一个元素。
使用 arr.length - 1
来计算给定数组的最后一个元素的索引并返回。
const last = arr => arr[arr.length - 1];
last([1, 2, 3]); // 3
longestItem
获取任何数量的可迭代对象或具有 length
属性的对象,并返回其中长度最长的一个。 如果多个对象具有相同的长度,则返回第一个对象。 如果没有提供参数,则返回 undefined
。
使用 Array.prototype.reduce()
,比较对象的 length
以找到长度最长的对象。
const longestItem = (...vals) => vals.reduce((a, x) => (x.length > a.length ? x : a));
longestItem('this', 'is', 'a', 'testcase'); // 'testcase' longestItem(...['a', 'ab', 'abc']); // 'abc' longestItem(...['a', 'ab', 'abc'], 'abcd'); // 'abcd' longestItem([1, 2, 3], [1, 2], [1, 2, 3, 4, 5]); // [1, 2, 3, 4, 5] longestItem([1, 2, 3], 'foobar'); // 'foobar'
mapObject
使用一个函数将数组的值映射到对象,在键值对中,原始值作为键,映射值作为值。
使用一个匿名的内部函数作用域来声明一个 undefined 的内存空间,使用闭包来存储返回值。 使用一个新的 Array
来存储带有函数映射的数组和一个逗号运算符来返回第二个步骤,而不需要从一个上下文移动到另一个上下文(由于闭包和操作顺序)。
const mapObject = (arr, fn) => (a => ( (a = [arr, arr.map(fn)]), a[0].reduce((acc, val, ind) => ((acc[val] = a[1][ind]), acc), {}) ))();
const squareIt = arr => mapObject(arr, a => a * a); squareIt([1, 2, 3]); // { 1: 1, 2: 4, 3: 9 }
maxN
从提供的数组中返回 n
个最大值元素。 如果 n
大于或等于提供的数组长度,则返回原始数组(按降序排列)。
使用 array.prototype.sort()
和 展开操作符 (...
) 对数组进行浅克隆,并按降序排序。 使用 Array.prototype.slice()
获取指定数量的元素。 省略第二个参数 n
,获得只有一个元素的数组。
const maxN = (arr, n = 1) => [...arr].sort((a, b) => b - a).slice(0, n);
maxN([1, 2, 3]); // [3] maxN([1, 2, 3], 2); // [3,2]
minN
从提供的数组中返回 n
个最小值元素。 如果 n
大于或等于提供的数组长度,则返回原始数组(按升序排列)。
使用 array.prototype.sort()
和 展开操作符 (...
) 对数组进行浅克隆,并按升序排序。 使用 Array.prototype.slice()
获取指定数量的元素。 省略第二个参数 n
,获得只有一个元素的数组。
const minN = (arr, n = 1) => [...arr].sort((a, b) => a - b).slice(0, n);
minN([1, 2, 3]); // [1] minN([1, 2, 3], 2); // [1,2]
none
如果提供的断言(predicate)函数处理集合中的所有元素都返回 false
,则返回 true
,否则返回 false
。
使用 Array.prototype.some()
测试集合中的任何元素是否基于 fn
返回 true
。 省略第二个参数 fn
,使用 Boolean
作为默认值。
const none = (arr, fn = Boolean) => !arr.some(fn);
none([0, 1, 3, 0], x => x == 2); // true none([0, 0, 0]); // true
nthElement
返回数组的第 n
个元素。
使用 array .prototype.slice()
首先获得一个包含第 n 个元素的数组。 如果索引超出界限,返回 undefined
。 省略第二个参数 n
,获得数组的第一个元素。
const nthElement = (arr, n = 0) => (n === -1 ? arr.slice(n) : arr.slice(n, n + 1))[0];
nthElement(['a', 'b', 'c'], 1); // 'b' nthElement(['a', 'b', 'b'], -3); // 'a'
推荐资源- ES6:正确的部分
学习新的ES6 JavaScript语言特性,如箭头函数,解构,生成器和更多的编写更干净,更有效,可读的程序。
offset
将指定数量的元素移动到数组的末尾。
两次使用 Array.prototype.slice()
来获取指定索引之后的元素和指定索引之前的元素。 使用展开操作符(...
)将两个数组合成一个数组。 如果 offset
为负数,元素将从结束移动到开始位置。
const offset = (arr, offset) => [...arr.slice(offset), ...arr.slice(0, offset)];
offset([1, 2, 3, 4, 5], 2); // [3, 4, 5, 1, 2] offset([1, 2, 3, 4, 5], -2); // [4, 5, 1, 2, 3]
partition
根据提供的函数对每个元素进行迭代,将元素分组为两个数组。
使用 array.prototype.reduce()
创建一个由两个数组组成的数组。 使用 array.prototype.push()
将 fn
返回 true
的元素添加到第一个数组,而 fn
返回 false
的元素添加到第二个数组。
const partition = (arr, fn) => arr.reduce( (acc, val, i, arr) => { acc[fn(val, i, arr) ? 0 : 1].push(val); return acc; }, [[], []] );
const users = [{ user: 'barney', age: 36, active: false }, { user: 'fred', age: 40, active: true }]; partition(users, o => o.active); // [[{ 'user': 'fred', 'age': 40, 'active': true }],[{ 'user': 'barney', 'age': 36, 'active': false }]]
permutations
⚠️ WARNING: This function's execution time increases exponentially with each array element. Anything more than 8 to 10 entries will cause your browser to hang as it tries to solve all the different combinations.
Generates all permutations of an array's elements (contains duplicates).
Use recursion. For each element in the given array, create all the partial permutations for the rest of its elements. Use Array.prototype.map()
to combine the element with each partial permutation, then Array.prototype.reduce()
to combine all permutations in one array. Base cases are for array length
equal to 2
or 1
.
const permutations = arr => { if (arr.length <= 2) return arr.length === 2 ? [arr, [arr[1], arr[0]]] : arr; return arr.reduce( (acc, item, i) => acc.concat( permutations([...arr.slice(0, i), ...arr.slice(i + 1)]).map(val => [item, ...val]) ), [] ); };
permutations([1, 33, 5]); // [ [ 1, 33, 5 ], [ 1, 5, 33 ], [ 33, 1, 5 ], [ 33, 5, 1 ], [ 5, 1, 33 ], [ 5, 33, 1 ] ]
pull
改变原始数组,过滤掉指定的值。
使用 Array.prototype.filter()
和 array.prototype.include()
过滤指定的值。 使用 Array.prototype.length = 0
通过将数组的长度重置为0来清空数组,并使用 array.prototype.push()
把提取的值重新填充数组。
(对于不改变原始数组的代码片段,请参阅 without
)
const pull = (arr, ...args) => { let argState = Array.isArray(args[0]) ? args[0] : args; let pulled = arr.filter((v, i) => !argState.includes(v)); arr.length = 0; pulled.forEach(v => arr.push(v)); };
let myArray = ['a', 'b', 'c', 'a', 'b', 'c']; pull(myArray, 'a', 'c'); // myArray = [ 'b', 'b' ]
pullAtIndex
改变原始数组,过滤掉指定索引的值。
使用 Array.prototype.filter()
和 array.prototype.include()
过滤指定的值。 使用 Array.prototype.length = 0
通过将数组的长度重置为0来清空数组,并使用 array.prototype.push()
把提取的值重新填充数组。 使用 Array.prototype.push()
跟踪提取的值。
const pullAtIndex = (arr, pullArr) => { let removed = []; let pulled = arr .map((v, i) => (pullArr.includes(i) ? removed.push(v) : v)) .filter((v, i) => !pullArr.includes(i)); arr.length = 0; pulled.forEach(v => arr.push(v)); return removed; };
let myArray = ['a', 'b', 'c', 'd']; let pulled = pullAtIndex(myArray, [1, 3]); // myArray = [ 'a', 'c' ] , pulled = [ 'b', 'd' ]
pullAtValue
修改原始数组,过滤掉指定的值。返回删除的元素。
使用 Array.prototype.filter()
和 array.prototype.include()
过滤指定的值。 使用 Array.prototype.length = 0
通过将数组的长度重置为0来清空数组,并使用 array.prototype.push()
把提取的值重新填充数组。 使用 Array.prototype.push()
跟踪提取的值。
const pullAtValue = (arr, pullArr) => { let removed = [], pushToRemove = arr.forEach((v, i) => (pullArr.includes(v) ? removed.push(v) : v)), mutateTo = arr.filter((v, i) => !pullArr.includes(v)); arr.length = 0; mutateTo.forEach(v => arr.push(v)); return removed; };
let myArray = ['a', 'b', 'c', 'a', 'b', 'c']; let pulled = pullAtValue(myArray, ['b', 'd']); // myArray = [ 'a', 'c' ] , pulled = [ 'b', 'd' ]
pullBy
根据给定的迭代器(iterator)函数,修改原始数组,过滤掉指定的值。
检查函数中是否提供了最后一个参数。 使用 array.prototype.map()
将迭代器函数 fn
应用于所有数组元素。 使用 Array.prototype.filter()
和 array.prototype.include()
过滤指定的值。 使用 Array.prototype.length = 0
通过将数组的长度重置为0来清空数组,并使用 array.prototype.push()
把提取的值重新填充数组。
const pullBy = (arr, ...args) => { const length = args.length; let fn = length > 1 ? args[length - 1] : undefined; fn = typeof fn == 'function' ? (args.pop(), fn) : undefined; let argState = (Array.isArray(args[0]) ? args[0] : args).map(val => fn(val)); let pulled = arr.filter((v, i) => !argState.includes(fn(v))); arr.length = 0; pulled.forEach(v => arr.push(v)); };
var myArray = [{ x: 1 }, { x: 2 }, { x: 3 }, { x: 1 }]; pullBy(myArray, [{ x: 1 }, { x: 3 }], o => o.x); // myArray = [{ x: 2 }]
reducedFilter
根据条件过滤一个对象数组,同时过滤掉未指定的键。
使用 array.prototype.filter()
根据断言函数 fn
对数组进行过滤,返回条件为真值(truthy)的对象。 在经过过滤后的数组上,使用 array.prototype.map()
和 array.prototype.reduce()
过滤掉在 keys
参数中未提供的键。
const reducedFilter = (data, keys, fn) => data.filter(fn).map(el => keys.reduce((acc, key) => { acc[key] = el[key]; return acc; }, {}) );
const data = [ { id: 1, name: 'john', age: 24 }, { id: 2, name: 'mike', age: 50 } ]; reducedFilter(data, ['id', 'name'], item => item.age > 24); // [{ id: 2, name: 'mike'}]
reduceSuccessive
【待翻译】
对数组中的每个元素(从左到右)都应用累加器(accumulator)函数,返回依次减少一个值的数组。
使用 array.prototype.reduce()
将给定函数应用于给定数组,存储每个得到的新结果。
const reduceSuccessive = (arr, fn, acc) => arr.reduce((res, val, i, arr) => (res.push(fn(res.slice(-1)[0], val, i, arr)), res), [acc]);
reduceSuccessive([1, 2, 3, 4, 5, 6], (acc, val) => acc + val, 0); // [0, 1, 3, 6, 10, 15, 21]
reduceWhich
将提供的函数设置比较规则后应用于数组,返回数组的最小/最大值。
使用 array.prototype.reduce()
结合 comparator
函数来获取数组中合适的元素。 您可以省略第二个参数 comparator
,默认返回数组中最小的元素。
const reduceWhich = (arr, comparator = (a, b) => a - b) => arr.reduce((a, b) => (comparator(a, b) >= 0 ? b : a));
reduceWhich([1, 3, 2]); // 1 reduceWhich([1, 3, 2], (a, b) => b - a); // 3 reduceWhich( [{ name: 'Tom', age: 12 }, { name: 'Jack', age: 18 }, { name: 'Lucy', age: 9 }], (a, b) => a.age - b.age ); // {name: "Lucy", age: 9}
reject
注:过滤掉符合断言函数条件的值
接受断言函数和数组,使用 array .prototype.filter()
,但仅当 pred(x) === false
时才保留 x
。
const reject = (pred, array) => array.filter((...args) => !pred(...args));
reject(x => x % 2 === 0, [1, 2, 3, 4, 5]); // [1, 3, 5] reject(word => word.length > 4, ['Apple', 'Pear', 'Kiwi', 'Banana']); // ['Pear', 'Kiwi']
remove
从数组中移除给定函数返回 false
的元素。
使用 Array.prototype.filter()
和 Array.prototype.reduce()
来查找数组中返回真值的元素,使用 Array.prototype.splice()
来移除元素。 func
有三个参数 (value, index, array
)。
const remove = (arr, func) => Array.isArray(arr) ? arr.filter(func).reduce((acc, val) => { arr.splice(arr.indexOf(val), 1); return acc.concat(val); }, []) : [];
remove([1, 2, 3, 4], n => n % 2 === 0); // [2, 4]
sample
从数组中返回一个随机元素。
使用 Math.random()
生成随机数,将其乘以 length
,并使用 Math.floor()
将其四舍五入到最近的整数。 这个方法也适用于字符串。
const sample = arr => arr[Math.floor(Math.random() * arr.length)];
sample([3, 7, 9, 11]); // 9
sampleSize
从 array
中获取 n
个唯一键随机元素。
使用 Fisher-Yates algorithm算法 对数组进行打乱。 使用Array.prototype.slice()
获取 n
个元素。 省略第二个参数 n
, 从数组中随机获取 1 个元素。
const sampleSize = ([...arr], n = 1) => { let m = arr.length; while (m) { const i = Math.floor(Math.random() * m--); [arr[m], arr[i]] = [arr[i], arr[m]]; } return arr.slice(0, n); };
sampleSize([1, 2, 3], 2); // [3,1] sampleSize([1, 2, 3], 4); // [2,3,1]
shank
具有与Array.prototype.splice()
相同的功能,但是 Array.prototype.splice()
返回一个新数组,而不是修改原始数组。
在删除现有元素 和/或 添加新元素之后,使用 array.prototype.slice()
和 array.prototype.concat()
获得一个包含新内容的新数组。 省略第二个参数 index
,下标从 0
开始。 省略第三个参数 delCount
,删除 0
个元素。 省略第四个参数 elements
,不添加任何新元素。
const shank = (arr, index = 0, delCount = 0, ...elements) => arr .slice(0, index) .concat(elements) .concat(arr.slice(index + delCount));
const names = ['alpha', 'bravo', 'charlie']; const namesAndDelta = shank(names, 1, 0, 'delta'); // [ 'alpha', 'delta', 'bravo', 'charlie' ] const namesNoBravo = shank(names, 1, 1); // [ 'alpha', 'charlie' ] console.log(names); // ['alpha', 'bravo', 'charlie']
const shuffle = ([...arr]) => { let m = arr.length; while (m) { const i = Math.floor(Math.random() * m--); [arr[m], arr[i]] = [arr[i], arr[m]]; } return arr; };
const foo = [1, 2, 3]; shuffle(foo); // [2, 3, 1], foo = [1, 2, 3]
similarity
返回两个数组的交集。
使用 Array.prototype.filter()
移除不属于 values
中的值,这些值由 array .prototype.include()
来确定。
const similarity = (arr, values) => arr.filter(v => values.includes(v));
similarity([1, 2, 3], [1, 2, 4]); // [1, 2]
sortedIndex
返回指定值插入到数组中的最小索引位置,以保持其排序顺序。
检查数组是否按降序(松散地)排序。 使用 Array.prototype.findIndex()
找到元素应该被插入的合适的索引位置。
const sortedIndex = (arr, n) => { const isDescending = arr[0] > arr[arr.length - 1]; const index = arr.findIndex(el => (isDescending ? n >= el : n <= el)); return index === -1 ? arr.length : index; };
sortedIndex([5, 3, 2, 1], 4); // 1 sortedIndex([30, 50], 40); // 1
sortedIndexBy
返回根据提供的迭代器函数,将指定值插入到数组中的最小索引位置,以保持其排序顺序。
检查数组是否按降序(松散地)排序。 使用 Array.prototype.findIndex()
根据迭代器函数 fn
查找应该插入元素的适当索引。
const sortedIndexBy = (arr, n, fn) => { const isDescending = fn(arr[0]) > fn(arr[arr.length - 1]); const val = fn(n); const index = arr.findIndex(el => (isDescending ? val >= fn(el) : val <= fn(el))); return index === -1 ? arr.length : index; };
sortedIndexBy([{ x: 4 }, { x: 5 }], { x: 4 }, o => o.x); // 0
sortedLastIndex
返回指定值插入到数组中的最大索引位置,以保持其排序顺序。
检查数组是否按降序(松散地)排序。 使用 Array.prototype.reverse()
和 Array.prototype.findIndex()
查找应该插入元素的最后一个适当的索引。
const sortedLastIndex = (arr, n) => { const isDescending = arr[0] > arr[arr.length - 1]; const index = arr.reverse().findIndex(el => (isDescending ? n <= el : n >= el)); return index === -1 ? 0 : arr.length - index; };
sortedLastIndex([10, 20, 30, 30, 40], 30); // 4
sortedLastIndexBy
返回根据提供的迭代器函数,将指定值插入到数组中的最大索引位置,以保持其排序顺序。
检查数组是否按降序(松散地)排序。 使用 array.prototype.map()
将迭代器函数应用于数组的所有元素。 使用 Array.prototype.reverse()
和 Array.prototype.findIndex()
根据提供的迭代器函数,查找应该插入元素的最后一个适当的索引。
const sortedLastIndexBy = (arr, n, fn) => { const isDescending = fn(arr[0]) > fn(arr[arr.length - 1]); const val = fn(n); const index = arr .map(fn) .reverse() .findIndex(el => (isDescending ? val <= el : val >= el)); return index === -1 ? 0 : arr.length - index; };
sortedLastIndexBy([{ x: 4 }, { x: 5 }], { x: 4 }, o => o.x); // 1
stableSort
对数组执行稳定排序,值相同时保留其初始索引。 不改变原始数组,而是返回新数组。
使用 array.prototype.map()
将输入数组的每个元素与其对应的索引配对。 使用 Array.prototype.sort()
和 compare
函数对列表进行排序,如果比较的值相等,则保留它们的初始顺序。 使用 array.prototype.map()
将其转换回初始数组项。
const stableSort = (arr, compare) => arr .map((item, index) => ({ item, index })) .sort((a, b) => compare(a.item, b.item) || a.index - b.index) .map(({ item }) => item);
const arr = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; const stable = stableSort(arr, () => 0); // [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
symmetricDifference
返回两个数组之间的差集,而不过滤重复的值。
根据每个数组创建一个 Set
,然后在每个数组上使用 array.prototype.filter()
,只保留不包含在另一个数组中的值。
const symmetricDifference = (a, b) => { const sA = new Set(a), sB = new Set(b); return [...a.filter(x => !sB.has(x)), ...b.filter(x => !sA.has(x))]; };
symmetricDifference([1, 2, 3], [1, 2, 4]); // [3, 4] symmetricDifference([1, 2, 2], [1, 3, 1]); // [2, 2, 3]
symmetricDifferenceBy
将提供的函数应用于两个数组的每个元素后,返回两个数组之间的差集。
根据每个数组创建一个 Set
,然后在每个数组上使用 array.prototype.filter()
,只保留不包含在另一个数组中的值。
const symmetricDifferenceBy = (a, b, fn) => { const sA = new Set(a.map(v => fn(v))), sB = new Set(b.map(v => fn(v))); return [...a.filter(x => !sB.has(fn(x))), ...b.filter(x => !sA.has(fn(x)))]; };
symmetricDifferenceBy([2.1, 1.2], [2.3, 3.4], Math.floor); // [ 1.2, 3.4 ]
symmetricDifferenceWith
使用提供的函数作为比较器,返回两个数组之间的差集。
使用 Array.prototype.filter()
和 Array.prototype.findIndex()
查找合适的值。
const symmetricDifferenceWith = (arr, val, comp) => [ ...arr.filter(a => val.findIndex(b => comp(a, b)) === -1), ...val.filter(a => arr.findIndex(b => comp(a, b)) === -1) ];
symmetricDifferenceWith( [1, 1.2, 1.5, 3, 0], [1.9, 3, 0, 3.9], (a, b) => Math.round(a) === Math.round(b) ); // [1, 1.2, 3.9]
tail
返回数组中除第一个元素外的所有元素。
如果数组的 length
大于 1
, ,则返回 Array.prototype.slice(1)
,否则返回整个数组。
const tail = arr => (arr.length > 1 ? arr.slice(1) : arr);
tail([1, 2, 3]); // [2,3] tail([1]); // [1]
take
返回从开头开始提取 n
个元素的数组。
使用 array.prototype.slice()
创建数组的一个切片,其中包含从开头开始提取的 n
个元素。
const take = (arr, n = 1) => arr.slice(0, n);
take([1, 2, 3], 5); // [1, 2, 3] take([1, 2, 3], 0); // []
takeRight
返回从结尾开始向前提取 n
个元素的数组。
使用 array.prototype.slice()
创建数组的一个切片,其中包含从结尾开始向前提取的 n
个元素。
const takeRight = (arr, n = 1) => arr.slice(arr.length - n, arr.length);
takeRight([1, 2, 3], 2); // [ 2, 3 ] takeRight([1, 2, 3]); // [3]
takeRightWhile
从数组末尾移除元素,直到传递的函数返回“true”。返回删除的元素。
const takeRightWhile = (arr, func) => arr.reduceRight((acc, el) => (func(el) ? acc : [el, ...acc]), []);
takeRightWhile([1, 2, 3, 4], n => n < 3); // [3, 4]
takeWhile
从数组的开头开始删除数组中的元素,直到传递的函数返回 true
。返回删除的元素。
循环遍历数组,使用 for...of
循环 Array.prototype.entries()
拿到的值, 直到函数返回的值为 true
为止。 使用 Array.prototype.slice()
返回删除的元素。
const takeWhile = (arr, func) => { for (const [i, val] of arr.entries()) if (func(val)) return arr.slice(0, i); return arr; };
takeWhile([1, 2, 3, 4], n => n >= 3); // [1, 2]
toHash
将给定的类数组简化为值哈希(value hash)(有键的数据存储)。
给定一个可迭代的类数组结构,在提供的对象上调用 Array.prototype.reduce.call()
逐个处理元素,并返回一个对象,该对象由键引用一个值。
const toHash = (object, key) => Array.prototype.reduce.call( object, (acc, data, index) => ((acc[!key ? index : data[key]] = data), acc), {} );
toHash([4, 3, 2, 1]); // { 0: 4, 1: 3, 2: 2, 3: 1 } toHash([{ a: 'label' }], 'a'); // { label: { a: 'label' } } // A more in depth example: let users = [{ id: 1, first: 'Jon' }, { id: 2, first: 'Joe' }, { id: 3, first: 'Moe' }]; let managers = [{ manager: 1, employees: [2, 3] }]; // We use function here because we want a bindable reference, but a closure referencing the hash would work, too. managers.forEach( manager => (manager.employees = manager.employees.map(function(id) { return this[id]; }, toHash(users, 'id'))) ); managers; // [ { manager:1, employees: [ { id: 2, first: "Joe" }, { id: 3, first: "Moe" } ] } ]
union
返回两个数组的并集,相同的元素只出现一次。
基于 a
和 b
创建一个 Set
对象,返回转换后的数组。
const union = (a, b) => Array.from(new Set([...a, ...b]));
union([1, 2, 3], [4, 3, 2]); // [1,2,3,4]
unionBy
将所提供的函数应用于两个数组的每个元素之后,返回两个数组的并集,相同的元素只出现一次。
在 fn
应用于 a
的所有元素后创建一个 Set
,并在 b
中过滤已经在集合中存在的元素。 最后返回一个转换为数组的集合。
const unionBy = (a, b, fn) => { const s = new Set(a.map(fn)); return Array.from(new Set([...a, ...b.filter(x => !s.has(fn(x)))])); };
unionBy([2.1], [1.2, 2.3], Math.floor); // [2.1, 1.2]
unionWith
使用提供的比较器函数,返回两个数组的并集,相同的元素只出现一次。
用 Array.prototype.findIndex()
使用提供的比较器函数后,在 b
中查找没有在 a
中匹配的值。
const unionWith = (a, b, comp) => Array.from(new Set([...a, ...b.filter(x => a.findIndex(y => comp(x, y)) === -1)]));
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]
uniqueElements
返回去重后的数组。
使用 ES6 的 Set
和 ...rest
运算符去除所有重复的值。
const uniqueElements = arr => [...new Set(arr)];
uniqueElements([1, 2, 2, 3, 4, 4, 5]); // [1, 2, 3, 4, 5]
uniqueElementsBy
根据提供的比较器函数,返回去重后的数组。
根据比较器函数 fn
, 使用 Array.prototype.reduce()
和 Array.prototype.some()
去除重复的值,只保留重复值中第一个出现的值。 比较器(comparator)函数接受两个参数:正在比较的两个元素的值。
const uniqueElementsBy = (arr, fn) => arr.reduce((acc, v) => { if (!acc.some(x => fn(v, x))) acc.push(v); return acc; }, []);
uniqueElementsBy( [ { id: 0, value: 'a' }, { id: 1, value: 'b' }, { id: 2, value: 'c' }, { id: 1, value: 'd' }, { id: 0, value: 'e' } ], (a, b) => a.id == b.id ); // [ { id: 0, value: 'a' }, { id: 1, value: 'b' }, { id: 2, value: 'c' } ]
uniqueElementsByRight
根据提供的比较器函数,从右边开始,返回去重后的数组。
根据比较器函数 fn
, 从右边开始,使用 Array.prototype.reduceRight()
和 Array.prototype.some()
去除重复的值,只保留重复值中最后一个出现的值。 比较器(comparator)函数接受两个参数:正在比较的两个元素的值。
const uniqueElementsByRight = (arr, fn) => arr.reduceRight((acc, v) => { if (!acc.some(x => fn(v, x))) acc.push(v); return acc; }, []);
uniqueElementsByRight( [ { id: 0, value: 'a' }, { id: 1, value: 'b' }, { id: 2, value: 'c' }, { id: 1, value: 'd' }, { id: 0, value: 'e' } ], (a, b) => a.id == b.id ); // [ { id: 0, value: 'e' }, { id: 1, value: 'd' }, { id: 2, value: 'c' } ]
uniqueSymmetricDifference
返回两个数组的差集,在两个数组中不重复的值。
在每个数组上使用 array.prototype.filter()
和 array .prototype.include()
来过滤另一个数组中包含的值,然后从结果中创建一个 Set
,删除重复的值。
const uniqueSymmetricDifference = (a, b) => [ ...new Set([...a.filter(v => !b.includes(v)), ...b.filter(v => !a.includes(v))]) ];
uniqueSymmetricDifference([1, 2, 3], [1, 2, 4]); // [3, 4] uniqueSymmetricDifference([1, 2, 2], [1, 3, 1]); // [2, 3]
unzip
创建一个数组,将 zip 生成的数组中的元素取消分组。
使用 Math.max.apply()
获取数组中最长子数组的长度,使用 Array.prototype.map()
生成最长长度个数组。 使用 Array.prototype.reduce()
和 Array.prototype.forEach()
将分组元素映射到对应的数组中。
const unzip = arr => arr.reduce( (acc, val) => (val.forEach((v, i) => acc[i].push(v)), acc), Array.from({ length: Math.max(...arr.map(x => x.length)) }).map(x => []) );
unzip([['a', 1, true], ['b', 2, false]]); // [['a', 'b'], [1, 2], [true, false]] unzip([['a', 1, true], ['b', 2]]); // [['a', 'b'], [1, 2], [true]]
unzipWith
创建一个数组,将 zip 生成的数组中的元素取消分组,并结合提供的函数生成最后的结果。
使用 Math.max.apply()
获取数组中最长子数组的长度,使用 Array.prototype.map()
生成最长长度个数组。 使用 Array.prototype.reduce()
和 Array.prototype.forEach()
将分组元素映射到对应的数组中。 使用 Array.prototype.map()
和展开操作符 (...
) 将 fn
应用于每一组元素。
const unzipWith = (arr, fn) => arr .reduce( (acc, val) => (val.forEach((v, i) => acc[i].push(v)), acc), Array.from({ length: Math.max(...arr.map(x => x.length)) }).map(x => []) ) .map(val => fn(...val));
unzipWith([[1, 10, 100], [2, 20, 200]], (...args) => args.reduce((acc, v) => acc + v, 0)); // [3, 30, 300]
without
过滤掉数组中具有指定值之一的元素。
使用 array.prototype.filter()
创建一个数组,排除(使用 !array.include()
)所有给定值。
(改变原始数组,请看 pull
) 代码片段
const without = (arr, ...args) => arr.filter(v => !args.includes(v));
without([2, 1, 2, 3], 1, 2); // [3]
xProd
将两个数组的每个元素两两进行组合,组合出所有的可能对存在数组中,返回一个存在所有可能性对的数组。
使用 Array.prototype.reduce()
, Array.prototype.map()
和 Array.prototype.concat()
从两个数组的元素中生成所有可能的对,并将它们保存在一个数组中。
const xProd = (a, b) => a.reduce((acc, x) => acc.concat(b.map(y => [x, y])), []);
xProd([1, 2], ['a', 'b']); // [[1, 'a'], [1, 'b'], [2, 'a'], [2, 'b']]
zip
创建一个根据原始数组中的位置进行分组的数组。
使用 Math.max.apply()
获取参数中最长的数组,创建一个长度为该长度的数组,并使用Array.from()
和映射函数(map-function) 来创建一个分组元素数组。 如果参数数组的长度不同,则在未找到值的情况下使用 undefined
。
const zip = (...arrays) => { const maxLength = Math.max(...arrays.map(x => x.length)); return Array.from({ length: maxLength }).map((_, i) => { return Array.from({ length: arrays.length }, (_, k) => arrays[k][i]); }); };
zip(['a', 'b'], [1, 2], [true, false]); // [['a', 1, true], ['b', 2, false]] zip(['a'], [1, 2], [true, false]); // [['a', 1, true], [undefined, 2, false]]
zipObject
给定一个有效属性标识符数组和一个值数组,返回一个将属性关联到值的对象。
由于对象可以有未定义的值,但不能有未定义的属性名,所以属性数组使用 array.prototype.reduce()
来决定结果对象的结构。
const zipObject = (props, values) => props.reduce((obj, prop, index) => ((obj[prop] = values[index]), obj), {});
zipObject(['a', 'b', 'c'], [1, 2]); // {a: 1, b: 2, c: undefined} zipObject(['a', 'b'], [1, 2, 3]); // {a: 1, b: 2}
zipWith
创建一个根据原始数组中的位置进行分组的数组,并使用函数作为最后一个参数来指定应如何组合分组中的值。
检查最后提供的参数是否为函数。 使用 Math.max.apply()
获取参数中最长的数组,创建一个长度为该长度的数组,并使用Array.from()
和映射函数(map-function) 来创建一个分组元素数组。 如果参数数组的长度不同,则在找不到值的地方使用“undefined”。 最后一个参数提供的函数应用于每个组 (...group)
的元素。
const zipWith = (...array) => { const fn = typeof array[array.length - 1] === 'function' ? array.pop() : undefined; return Array.from( { length: Math.max(...array.map(a => a.length)) }, (_, i) => (fn ? fn(...array.map(a => a[i])) : array.map(a => a[i])) ); };
zipWith([1, 2], [10, 20], [100, 200], (a, b, c) => a + b + c); // [111,222] zipWith( [1, 2, 3], [10, 20], [100, 200], (a, b, c) => (a != null ? a : 'a') + (b != null ? b : 'b') + (c != null ? c : 'c') ); // [111, 222, '3bc']