Lodash 函数列表 · 数组
chunk
将一个数组分成多个小数组
const chunk = (arr, size) =>
Array.from({ length: Math.ceil(arr.length / size) }, (v, i) =>
arr.slice(i * size, i * size + size)
);
chunk(['a', 'b', 'c', 'd'], 2);
// => [['a', 'b'], ['c', 'd']]
chunk(['a', 'b', 'c', 'd'], 3);
// => [['a', 'b', 'c'], ['d']]
思路:根据指定的大小将数组切割成多个小数组,使用 ES6 的 Array.from()方法,创建一个长度为切割后数组个数的新数组,使用 slice()方法将原数组按照切割后的大小进行分割,然后将每个小数组存储在新数组中返回。
compact
去除数组中的假值(false、null、0、""、undefined、NaN)
const compact = arr => arr.filter(Boolean);
compact([0, 1, false, 2, '', 3]);
// => [1, 2, 3]
思路:使用 filter()方法,过滤出数组中的真值,Boolean()函数将所有假值转化为 false,所有真值转化为 true。
concat
合并多个数组
const concat = (...args) => [].concat(...args);
const array = [1];
const other = concat(array, 2, [3], [[4]]);
console.log(other);
// => [1, 2, 3, [4]]
console.log(array);
// => [1]
思路:使用 ES6 的扩展运算符(...)将传入的参数转化为数组,然后使用 concat()方法将所有数组合并成一个新数组并返回。
difference
返回一个数组,包含在第一个数组中但不在其他数组中的元素
// // 第1种实现
// const difference = (arr, ...args) => arr.filter((item) => !args.flat().includes(item));
// 第2种实现
const difference = (arr, ...args) =>
arr.filter(item => args.every(arg => !arg.includes(item)));
difference([3, 2, 1], [4, 2]);
// => [3, 1]
思路:使用 filter()方法遍历第一个数组,使用 every()方法遍历其他数组,将第一个数组中不包含在其他数组中的元素过滤出来,返回一个新数组。
differenceBy
与 difference 类似,但是可以指定一个函数对比数组中的元素
const differenceBy = (array, values, iteratee) => {
const fn = typeof iteratee === 'function' ? iteratee : item => item[iteratee];
const valuesSet = new Set(values.map(fn));
return array.filter(item => !valuesSet.has(fn(item)));
};
differenceBy([3.1, 2.2, 1.3], [4.4, 2.5], Math.floor);
// => [3.1, 1.3]
// The `property` iteratee shorthand.
differenceBy([{ x: 2 }, { x: 1 }], [{ x: 1 }], 'x');
// => [{ 'x': 2 }]
思路:先判断第三个参数是否为函数,如果是则使用函数对比数组中的元素进行差异筛选,否则直接使用 lodash 的差异筛选函数来实现。
differenceWith
从第一个数组中过滤出第二个数组中没有的元素,使用一个自定义比较函数进行比较。
const differenceWith = (array, values, comparator) =>
array.filter(item => !values.some(value => comparator(item, value)));
const objects = [
{ x: 1, y: 2 },
{ x: 2, y: 1 },
];
_.differenceWith(objects, [{ x: 1, y: 2 }], _.isEqual);
// => [{ 'x': 2, 'y': 1 }]
思路:利用高阶函数 filter 和 some 对两个数组进行比较,返回第一个数组中不包含在第二个数组中的元素。
drop
返回一个新数组,去掉原数组中的前 n 个元素
const drop = (arr, n = 1) => arr.slice(n);
drop([1, 2, 3]);
// => [2, 3]
drop([1, 2, 3], 2);
// => [3]
drop([1, 2, 3], 5);
// => []
drop([1, 2, 3], 0);
// => [1, 2, 3]
思路:使用 slice()方法将原数组中的前 n 个元素删除并返回。
dropRight
返回一个新数组,去掉原数组中的后 n 个元素
const dropRight = (arr, n = 1) =>
n >= arr.length ? [] : arr.slice(0, arr.length - n);
dropRight([1, 2, 3]);
// => [1, 2]
dropRight([1, 2, 3], 2);
// => [1]
dropRight([1, 2, 3], 5);
// => []
dropRight([1, 2, 3], 0);
// => [1, 2, 3]
思路:根据 n 的值,通过数组的 slice 方法获取新的数组,从而实现删除末尾元素的操作。
dropRightWhile
返回一个新数组,去掉原数组中从最后一个符合条件的元素到结尾之间的元素
const dropRightWhile = (array, iteratee) => {
let right = array.length - 1;
if (typeof iteratee === 'function') {
while (iteratee(array[right])) {
right--;
}
}
if (typeof iteratee === 'object' && !Array.isArray(iteratee)) {
const entries = Object.entries(iteratee);
while (entries.every(([key, value]) => array[right][key] === value)) {
right--;
}
}
if (Array.isArray(iteratee) && iteratee.length === 2) {
const [key, value] = iteratee;
while (array[right][key] === value) {
right--;
}
}
return array.slice(0, right + 1);
};
const users = [
{ user: 'barney', active: true },
{ user: 'fred', active: false },
{ user: 'pebbles', active: false },
];
dropRightWhile(users, o => !o.active);
// => objects for ['barney']
// The `matches` iteratee shorthand.
dropRightWhile(users, { user: 'pebbles', active: false });
// => objects for ['barney', 'fred']
// The `matchesProperty` iteratee shorthand.
dropRightWhile(users, ['active', false]);
// => objects for ['barney']
// The `property` iteratee shorthand.
dropRightWhile(users, 'active');
// => objects for ['barney', 'fred', 'pebbles']
思路:该函数实现了一个从数组末尾开始遍历,当元素满足传入的迭代器条件时,将该元素从数组中删除并返回删除后的新数组的函数。迭代器可以是函数、对象或数组。
fill
用指定的值填充数组
const fill = (arr, value, start = 0, end = arr.length) =>
arr.fill(value, start, end);
const array = [1, 2, 3];
fill(array, 'a');
console.log(array);
// => ['a', 'a', 'a']
fill(Array(3), 2);
// => [2, 2, 2]
fill([4, 6, 8, 10], '*', 1, 3);
// => [4, '*', '*', 10]
思路:使用 fill()方法将数组的指定位置开始到指定位置结束的元素替换成指定的值,并返回修改后的数组。
findIndex
返回第一个符合条件的元素的下标
const findIndex = (arr, fn) => arr.findIndex(fn);
const users = [
{ user: 'barney', active: false },
{ user: 'fred', active: false },
{ user: 'pebbles', active: true },
];
findIndex(users, o => o.user === 'barney');
// => 0
// The `matches` iteratee shorthand.
findIndex(users, { user: 'fred', active: false });
// => 1
// The `matchesProperty` iteratee shorthand.
findIndex(users, ['active', false]);
// => 0
// The `property` iteratee shorthand.
findIndex(users, 'active');
// => 2
思路:使用 findIndex()方法查找符合条件的元素在数组中的下标,如果没有找到则返回-1。
findLastIndex
返回最后一个符合条件的元素的下标
const findLastIndex = (arr, predicate) => {
if (typeof predicate === 'function') {
for (let i = arr.length - 1; i >= 0; i--) {
if (predicate(arr[i], i, arr)) {
return i;
}
}
} else if (Array.isArray(predicate)) {
const [key, value] = predicate;
for (let i = arr.length - 1; i >= 0; i--) {
if (arr[i][key] === value) {
return i;
}
}
} else if (typeof predicate === 'object') {
for (let i = arr.length - 1; i >= 0; i--) {
const keys = Object.keys(predicate);
const match = keys.every(key => predicate[key] === arr[i][key]);
if (match) {
return i;
}
}
} else {
for (let i = arr.length - 1; i >= 0; i--) {
if (arr[i] && arr[i][predicate]) {
return i;
}
}
}
return -1;
};
const users = [
{ user: 'barney', active: true },
{ user: 'fred', active: false },
{ user: 'pebbles', active: false },
];
findLastIndex(users, o => o.user === 'pebbles');
// => 2
// The `matches` iteratee shorthand.
findLastIndex(users, { user: 'barney', active: true });
// => 0
// The `matchesProperty` iteratee shorthand.
findLastIndex(users, ['active', false]);
// => 2
// The `property` iteratee shorthand.
findLastIndex(users, 'active');
// => 0
思路:使用 findLastIndex()方法,返回数组中满足提供的测试函数条件的最后一个元素的索引。若没有找到对应元素,则返回 -1
head
返回数组中的第一个元素
const head = arr => arr[0];
head([1, 2, 3]);
// => 1
head([]);
// => undefined
思路:直接返回数组的第一个元素。
flatten
将多维数组转化为一维数组
const flatten = arr => [].concat(...arr);
flatten([1, [2, [3, [4]], 5]]);
// => [1, 2, [3, [4]], 5]
思路:使用扩展运算符展开多维数组,再使用 concat 方法将展开后的一维数组拼接起来,得到最终的一维数组。
flattenDeep
将多维数组转化为一维数组,递归进行
const flattenDeep = arr =>
[].concat(...arr.map(v => (Array.isArray(v) ? flattenDeep(v) : v)));
flattenDeep([1, [2, [3, [4]], 5]]);
// => [1, 2, 3, 4, 5]
思路:使用 Array.map 遍历数组,对于数组中的每个元素,如果是数组则递归调用 flattenDeep 函数,否则直接返回该元素,最终使用扩展运算符展开数组,并使用 concat 方法拼接起来。
fromPairs
将一个二维数组转化为一个对象
const fromPairs = arr =>
arr.reduce((obj, [key, val]) => ({ ...obj, [key]: val }), {});
fromPairs([
['a', 1],
['b', 2],
]);
// => { 'a': 1, 'b': 2 }
思路:使用 Array.reduce 遍历数组,对于数组中的每个元素,将其解构为 key 和 val,并将其添加到一个新对象中,最终得到一个包含所有 key-value 对的对象。
indexOf
返回一个元素在数组中的下标,从前往后找
const indexOf = (arr, val, fromIndex = 0) =>
arr.findIndex((item, index) => index >= fromIndex && item === val);
indexOf([1, 2, 1, 2], 2);
// => 1
// Search from the `fromIndex`.
indexOf([1, 2, 1, 2], 2, 2);
// => 3
思路:使用数组的 findIndex 方法查找,并且支持从指定索引位置开始查找。
initial
返回一个新数组,去掉原数组中的最后一个元素
const initial = arr => arr.slice(0, -1);
initial([1, 2, 3]);
// => [1, 2]
思路:使用数组的 slice 方法截取出除了最后一个元素的部分,得到一个新数组。
intersection
返回一个数组,包含在所有数组中都存在的元素
const intersection = (...arr) => [
...new Set(arr.reduce((a, b) => a.filter(v => b.includes(v)))),
];
intersection([2, 1], [4, 2], [1, 2]);
// => [2]
思路:使用数组的 reduce 方法遍历所有数组,使用 filter 方法筛选出在当前数组中也存在的元素,最后使用 Set 去重并转换为数组。
join
将数组转化为字符串,并用指定的分隔符分隔
const join = (arr, separator = ',') =>
arr.reduce((res, val, i) => `${res}${i ? separator : ''}${val}`, '');
join(['a', 'b', 'c'], '~');
// => 'a~b~c'
思路:使用 reduce 方法遍历数组,将每个元素和分隔符拼接起来,最终得到一个拼接好的字符串。
last
返回数组中的最后一个元素
const last = arr => arr[arr.length - 1];
last([1, 2, 3]);
// => 3
思路:返回数组中的最后一个元素。
lastIndexOf
返回一个元素在数组中的下标,从后往前找
const lastIndexOf = (arr, val) => arr.lastIndexOf(val);
lastIndexOf([1, 2, 1, 2], 2);
// => 3
// Search from the `fromIndex`.
lastIndexOf([1, 2, 1, 2], 2, 2);
// => 1
思路:使用数组的 lastIndexOf 方法查找元素在数组中的下标。
pull
从数组中去掉指定的元素
const pull = (arr, ...args) => arr.filter(item => !args.includes(item));
const array = [1, 2, 3, 1, 2, 3];
pull(array, 2, 3);
console.log(array);
// => [1, 1]
思路:通过 filter 方法筛选掉不需要的元素即可。
pullAt
从数组中取出指定下标的元素,并返回一个新数组
const pullAt = (arr, ...args) => args.map(index => arr.splice(index, 1)[0]);
const array = [5, 10, 15, 20];
const evens = pullAt(array, 1, 3);
console.log(array);
// => [5, 15]
console.log(evens);
// => [10, 20]
思路:map() 方法遍历传入的下标数组,通过 splice() 方法从原数组中删除相应的元素并返回。
reverse
反转数组
const reverse = arr => [...arr].reverse();
const array = [1, 2, 3];
reverse(array);
// => [3, 2, 1]
console.log(array);
// => [3, 2, 1]
思路:利用解构赋值和 reverse() 方法即可。
slice
返回一个新数组,从原数组中截取指定范围的元素
const slice = (arr, start, end) => arr.slice(start, end);
思路:直接调用原生的 slice() 方法。
sortedIndex
返回一个元素应该插入到数组中的下标
const sortedIndex = (arr, value) => {
let left = 0;
let right = arr.length;
while (left < right) {
const mid = Math.floor((left + right) / 2);
if (arr[mid] < value) {
left = mid + 1;
} else {
right = mid;
}
}
return right;
};
sortedIndex([30, 50], 40);
// => 1
思路:二分查找算法实现,找到元素应该插入的位置。
tail
返回一个新数组,去掉原数组中的第一个元素
const tail = arr => arr.slice(1);
tail([1, 2, 3]);
// => [2, 3]
思路:利用 slice() 方法去掉第一个元素即可。
take
返回一个新数组,包含原数组中前 n 个元素
const take = (arr, n = 1) => arr.slice(0, n);
take([1, 2, 3]);
// => [1]
take([1, 2, 3], 2);
// => [1, 2]
take([1, 2, 3], 5);
// => [1, 2, 3]
take([1, 2, 3], 0);
// => []
思路:直接调用原生的 slice() 方法,注意默认参数。
takeRight
返回一个新数组,包含原数组中后 n 个元素
const takeRight = (arr, n = 1) => arr.slice(-n);
takeRight([1, 2, 3]);
// => [3]
takeRight([1, 2, 3], 2);
// => [2, 3]
takeRight([1, 2, 3], 5);
// => [1, 2, 3]
takeRight([1, 2, 3], 0);
// => []
思路:同样直接调用原生的 slice() 方法,注意负数下标的使用。
union
返回一个新数组,包含所有数组中的不重复元素
const union = (...args) => [...new Set(args.flat())];
union([2], [1, 2]);
// => [2, 1]
思路:flat() 方法将多维数组转为一维,Set 数据结构去重,再转回数组即可。
uniq
返回一个新数组,包含所有数组中的不重复元素
const uniq = arr => [...new Set(arr)];
uniq([2, 1, 2]);
// => [2, 1]
思路:同样利用 Set() 数据结构去重。
without
返回一个新数组,去掉原数组中指定的元素
const without = (arr, ...args) => arr.filter(item => !args.includes(item));
without([2, 1, 2, 3], 1, 2);
// => [3]
思路:同 pull 方法。
xor
返回一个新数组,包含只在其中一个数组中出现过的元素
const xor = (...args) =>
args
.flat()
.filter(
item => args.flat().indexOf(item) === args.flat().lastIndexOf(item)
);
xor([2, 1], [2, 3]);
// => [1, 3]
思路:flat() 方法转换成一维数组,然后利用 filter() 方法和 indexOf()、lastIndexOf() 方法判断出只在一个数组中出现过的元素。
zip
将多个数组的同一位置的元素合并为一个数组
const zip = (...arrays) =>
arrays[0].map((_, i) => arrays.map(array => array[i]));
zip(['fred', 'barney'], [30, 40], [true, false]);
// => [['fred', 30, true], ['barney', 40, false]]
思路:使用了 Rest 参数,首先取出第一个数组,然后使用 map 遍历第一个数组的长度,通过索引遍历所有数组的该索引元素,将其组合成一个新的数组并返回。
unzip
将 zip 函数生成的数组还原成原始的数组
const unzip = array =>
array.reduce(
(acc, val) => (val.forEach((v, i) => acc[i].push(v)), acc),
Array.from({ length: Math.max(...array.map(a => a.length)) }).map(() => [])
);
const zipped = zip(['fred', 'barney'], [30, 40], [true, false]);
// => [['fred', 30, true], ['barney', 40, false]]
unzip(zipped);
// => [['fred', 'barney'], [30, 40], [true, false]]
思路:使用 reduce 遍历 zip 函数生成的数组,将每个元素的每个值取出来,根据索引组成新的数组返回。在 reduce 函数的初始值中,使用了 Math.max 获取所有元素中最大长度,并通过 Array.from 创建对应长度的二维数组。
dropWhile
返回一个新数组,去掉原数组中从开始到第一个符合条件的元素之间的元素
const dropWhile = (array, predicate) =>
array.slice(array.findIndex(val => !predicate(val)));
const users = [
{ user: 'barney', active: false },
{ user: 'fred', active: false },
{ user: 'pebbles', active: true },
];
dropWhile(users, o => !o.active);
// => objects for ['pebbles']
// The `matches` iteratee shorthand.
dropWhile(users, { user: 'barney', active: false });
// => objects for ['fred', 'pebbles']
// The `matchesProperty` iteratee shorthand.
dropWhile(users, ['active', false]);
// => objects for ['pebbles']
// The `property` iteratee shorthand.
dropWhile(users, 'active');
// => objects for ['barney', 'fred', 'pebbles']
思路:使用 findIndex 函数找到第一个不符合条件的元素,然后使用 slice 函数截取该元素之后的数组并返回。
intersectionBy
与 intersection 类似,但是可以指定一个函数对比数组中的元素
const intersectionBy = (arr1, arr2, compareFn) =>
arr1.filter(item =>
arr2.some(compareItem => compareFn(item) === compareFn(compareItem))
);
intersectionBy([2.1, 1.2], [4.3, 2.4], Math.floor);
// => [2.1]
// The `property` iteratee shorthand.
intersectionBy([{ x: 1 }], [{ x: 2 }, { x: 1 }], 'x');
// => [{ 'x': 1 }]
思路:使用数组的 filter 方法遍历第一个数组,并使用参数指定的函数对比第二个数组的每一个元素,最终返回两个数组的交集。
pullAll
与 pull 类似,但是接收一个数组作为参数
const pullAll = (arr, values) => arr.filter(item => !values.includes(item));
const array = [1, 2, 3, 1, 2, 3];
pullAll(array, [2, 3]);
console.log(array);
// => [1, 1]
思路:使用数组的 filter 方法遍历原数组,排除传入的数组中存在的元素。
pullAllBy
与 pullBy 类似,但是接收一个数组作为参数
const pullAllBy = (arr, values, compareFn) =>
arr.filter(
item =>
!values.some(compareItem => compareFn(item) === compareFn(compareItem))
);
const array = [{ x: 1 }, { x: 2 }, { x: 3 }, { x: 1 }];
pullAllBy(array, [{ x: 1 }, { x: 3 }], 'x');
console.log(array);
// => [{ 'x': 2 }]
思路:使用数组的 filter 方法遍历原数组,排除传入的数组中存在的元素,使用参数指定的函数对比两个数组中的元素。
pullAllWith
与 pullWith 类似,但是接收一个数组作为参数
const pullAllWith = (arr, values, compareFn) =>
arr.filter(item => !values.some(compareItem => compareFn(item, compareItem)));
const array = [
{ x: 1, y: 2 },
{ x: 3, y: 4 },
{ x: 5, y: 6 },
];
pullAllWith(array, [{ x: 3, y: 4 }], isEqual);
console.log(array);
// => [{ 'x': 1, 'y': 2 }, { 'x': 5, 'y': 6 }]
思路:使用数组的 filter 方法遍历原数组,排除传入的数组中存在的元素,使用参数指定的函数对比两个数组中的元素。
sortedIndexOf
与 indexOf 类似,但是可以在已排序的数组中使用
const sortedIndexOf = (arr, value) => {
let left = 0;
let right = arr.length - 1;
while (left <= right) {
const mid = Math.floor((left + right) / 2);
if (arr[mid] === value) {
return mid;
}
if (arr[mid] < value) {
left = mid + 1;
} else {
right = mid - 1;
}
}
return -1;
};
sortedIndexOf([4, 5, 5, 5, 6], 5);
// => 1
思路:使用二分查找算法在已排序的数组中查找指定元素的位置。
sortedLastIndexOf
与 lastIndexOf 类似,但是可以在已排序的数组中使用
const sortedLastIndexOf = (arr, value) => {
let left = 0;
let right = arr.length - 1;
let lastIndex = -1;
while (left <= right) {
const mid = Math.floor((left + right) / 2);
if (arr[mid] === value) {
lastIndex = mid;
left = mid + 1;
} else if (arr[mid] < value) {
left = mid + 1;
} else {
right = mid - 1;
}
}
return lastIndex;
};
sortedLastIndex([4, 5, 5, 5, 6], 5);
// => 4
思路:使用二分查找算法在已排序的数组中查找指定元素的最后一个位置。
sortedUniq
与 uniq 类似,但是可以在已排序的数组中使用
const sortedUniq = arr =>
arr.reduce((result, item) => {
if (result.length === 0 || result[result.length - 1] !== item) {
result.push(item);
}
return result;
}, []);
sortedUniq([1, 1, 2]);
// => [1, 2]
思路:使用数组的 reduce 方法和 indexOf 方法过滤掉重复元素,并返回新数组。
sortedUniqBy
与 uniqBy 类似,但是可以在已排序的数组中使用
const sortedUniqBy = (array, iteratee) =>
array.reduce(
(result, value) =>
result.length && iteratee(value) === iteratee(result[result.length - 1])
? result
: [...result, value],
[]
);
sortedUniqBy([1.1, 1.2, 2.3, 2.4], Math.floor);
// => [1.1, 2.3]
思路:使用 reduce 方法,对原数组进行遍历,将每个元素通过指定函数转化为一个值,并使用 Set 对象来去重,最终返回去重后的数组。
takeWhile
返回一个新数组,包含原数组中从开始到第一个不符合条件的元素之间的元素
const takeWhile = (array, predicate) =>
array.slice(
0,
array.findIndex(element => !predicate(element))
);
思路:使用 findIndex 方法,查找第一个不符合条件的元素的索引,然后使用 slice 方法截取原数组中符合条件的部分,返回新数组。
takeRightWhile
返回一个新数组,包含原数组中从最后一个不符合条件的元素到结尾之间的元素
const takeRightWhile = (array, predicate) =>
array
.reverse()
.slice(
0,
array.findIndex(element => !predicate(element))
)
.reverse();
const users = [
{ user: 'barney', active: true },
{ user: 'fred', active: false },
{ user: 'pebbles', active: false },
];
takeRightWhile(users, o => !o.active);
// => objects for ['fred', 'pebbles']
// The `matches` iteratee shorthand.
takeRightWhile(users, { user: 'pebbles', active: false });
// => objects for ['pebbles']
// The `matchesProperty` iteratee shorthand.
takeRightWhile(users, ['active', false]);
// => objects for ['fred', 'pebbles']
// The `property` iteratee shorthand.
takeRightWhile(users, 'active');
// => []
思路:使用 reverse 方法反转原数组,然后使用 findIndex 方法查找反转后数组中第一个不符合条件的元素的索引,最终使用 slice 方法截取原数组中从该索引到结尾的部分,返回新数组。
unionBy
与 union 类似,但是可以指定一个函数对比数组中的元素
const unionBy = (...arrays) => {
const iteratee = arrays.pop();
const unionSet = new Set(
arrays.reduce((result, array) => [...result, ...array], []).map(iteratee)
);
return Array.from(unionSet);
};
unionBy([2.1], [1.2, 2.3], Math.floor);
// => [2.1, 1.2]
// The `property` iteratee shorthand.
unionBy([{ x: 1 }], [{ x: 2 }, { x: 1 }], 'x');
// => [{ 'x': 1 }, { 'x': 2 }]
思路:使用 Set 对象进行数组去重,通过指定函数将多个数组中的元素转化为同一值,最终将去重后的值转化为数组返回。
uniqBy
与 uniq 类似,但是可以指定一个函数对比数组中的元素
const uniqBy = (array, iteratee) => {
const uniqSet = new Set(array.map(iteratee));
return Array.from(uniqSet).map(value =>
array.find(element => iteratee(element) === value)
);
};
uniqBy([2.1, 1.2, 2.3], Math.floor);
// => [2.1, 1.2]
// The `property` iteratee shorthand.
uniqBy([{ x: 1 }, { x: 2 }, { x: 1 }], 'x');
// => [{ 'x': 1 }, { 'x': 2 }]
思路:同 unionBy 方法实现思路类似。
unzipWith
与 unzip 类似,但是可以指定一个函数来处理 zip 函数生成的数组
const unzipWith = (array, iteratee) =>
array.reduce(
(result, value) => (
value.forEach((innerValue, index) =>
result[index].push(iteratee ? iteratee(innerValue) : innerValue)
),
result
),
Array.from({ length: Math.max(...array.map(value => value.length)) }).map(
() => []
)
);
const zipped = zip([1, 2], [10, 20], [100, 200]);
// => [[1, 10, 100], [2, 20, 200]]
unzipWith(zipped, add);
// => [3, 30, 300]
思路:使用 reduce 方法,对传入的数组进行遍历,将每个子数组进行传入的函数处理后,将处理后的值存储到对应索引位置上,最终返回处理后的数组。
xorBy
与 xor 类似,但是可以指定一个函数对比数组中的元素
const xorBy = (...arrays) => {
const iteratee = arrays.pop();
const valueCount = new Map();
arrays
.reduce((result, array) => [...result, ...array], [])
.forEach((value) => {
const newValue = iteratee(value);
xorBy([2.1, 1.2], [2.3, 3.4], Math.floor);
// => [1.2, 3.4]
// The `property` iteratee shorthand.
xorBy([{ 'x': 1 }], [{ 'x': 2 }, { 'x': 1 }], 'x');
// => [{ 'x': 2 }]
思路:使用 reduce 方法,对传入的多个数组进行遍历,将每个数组中的元素转化为指定值,并使用 Map 对象统计每个值出现的次数,最后返回出现次数为 1 的元素组成的数组。
zipObject
将两个数组转化为一个对象
const zipObject = (keys, values) =>
keys.reduce((obj, key, i) => ({ ...obj, [key]: values[i] }), {});
zipObject(['a', 'b'], [1, 2]);
// => { 'a': 1, 'b': 2 }
思路:使用 reduce 函数遍历 keys 数组,每次将 keys 数组中的一个元素作为属性名,values 数组中相同位置的元素作为属性值,然后将它们存入一个新对象中,最后返回该对象。
zipObjectDeep
将两个数组转化为一个嵌套对象
const zipObjectDeep = (keys, values) =>
keys.reduce((obj, key, i) => {
const path = key.split('.');
const lastKey = path.pop();
const nestedObj = path.reduceRight(
(nested, prop) => ({ [prop]: nested }),
values[i]
);
return mergeWith(obj, { [lastKey]: nestedObj }, customizer);
}, {});
zipObjectDeep(['a.b[0].c', 'a.b[1].d'], [1, 2]);
// => { 'a': { 'b': [{ 'c': 1 }, { 'd': 2 }] } }
思路:使用 reduce 函数遍历 keys 数组,每次将 keys 数组中的一个元素拆分成一个路径数组,使用 reduceRight 函数从路径数组的最后一个元素开始遍历,每次将该元素作为属性名,前一个元素对应的对象作为属性值,然后将它们存入一个新对象中,最后返回该对象。
- 感谢你赐予我前进的力量