常用数组方法小记
官网
数组
比较两个数组里面的不同项
const difference = (a, b) => {
const s = new Set(b);
return a.filter(x => !s.has(x));
};
EXAMPLES
difference([1, 2, 3], [1, 2, 4]); // [3]
比较两个数组里面的不同项,通过特定条件
const differenceBy = (a, b, fn) => {
const s = new Set(b.map(fn));
return a.map(fn).filter(el => !s.has(el));
};
EXAMPLES
differenceBy([2.1, 1.2], [2.3, 3.4], Math.floor); // [1]
differenceBy([{ x: 2 }, { x: 1 }], [{ x: 1 }], v => v.x); // [2]
去除数组中json的重复项,从最后一位开始算
//
const uniqueElementsByRight = (arr, fn) =>
arr.reduceRight((acc, v) => {
if (!acc.some(x => fn(v, x))) acc.push(v);
return acc;
}, []);
// EXAMPLES
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' } ]
去除数组中json的重复项,从第一位开始算
const uniqueElementsBy = (arr, fn) =>
arr.reduce((acc, v) => {
if (!acc.some(x => fn(v, x))) acc.push(v);
return acc;
}, []);
// EXAMPLES
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' } ]
前后数相加
const reduceSuccessive = (arr, fn, acc) =>
arr.reduce((res, val, i, arr) => (res.push(fn(res.slice(-1)[0], val, i, arr)), res), [acc]);
// EXAMPLES
reduceSuccessive([1, 2, 3, 4, 5, 6], (acc, val) => acc + val, 0); // [0, 1, 3, 6, 10, 15, 21]
从数组中找最后一项
const findLastIndex = (arr, fn) =>
(arr
.map((val, i) => [i, val])
.filter(([i, val]) => fn(val, i, arr))
.pop() || [-1])[0];
// EXAMPLES
findLastIndex([1, 2, 3, 4], n => n % 2 === 1); // 2 (index of the value 3)
findLastIndex([1, 2, 3, 4], n => n === 5); // -1 (default value when not found)
根据条件过滤数组
const reducedFilter = (data, keys, fn) =>
data.filter(fn).map(el =>
keys.reduce((acc, key) => {
acc[key] = el[key];
return acc;
}, {})
);
// EXAMPLES
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'}]
查找最大值,并返回他的索引值
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;
};
// EXAMPLES
sortedLastIndexBy([{ x: 4 }, { x: 5 }], { x: 4 }, o => o.x); // 1
过滤数组中的非唯一值
const filterNonUniqueBy = (arr, fn) =>
arr.filter((v, i) => arr.every((x, j) => (i === j) === fn(v, x, i, j)));
// EXAMPLES
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' } ]
比较两个数组中的相同项
const intersectionWith = (a, b, comp) => a.filter(x => b.findIndex(y => comp(x, y)) !== -1);
// EXAMPLES
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]
intersectionWith([1, 1.2, 1.5, 3, 0], [1.9, 3, 0, 3.9], (a, b) => a === b); // [3, 0]
返回数组中的第一项
const head = arr => (arr && arr.length ? arr[0] : undefined);
// EXAMPLES
head([1, 2, 3]); // 1
head([]); // undefined
head(null); // undefined
head(undefined); // undefined
返回数组中的最后一项
const last = arr => (arr && arr.length ? arr[arr.length - 1] : undefined);
// EXAMPLES
last([1, 2, 3]); // 3
last([]); // undefined
last(null); // undefined
last(undefined); // undefined
返回数组中的最大值或者最小值
const reduceWhich = (arr, comparator = (a, b) => a - b) =>
arr.reduce((a, b) => (comparator(a, b) >= 0 ? b : a));
// EXAMPLES
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}
reduceWhich(
[{ name: 'Tom', age: 12 }, { name: 'Jack', age: 18 }, { name: 'Lucy', age: 9 }],
(a, b) => b.age - a.age
); // {name: "Jack", age: 18}
返回特定条件下的数组
const takeRightWhile = (arr, func) =>
arr.reduceRight((acc, el) => (func(el) ? acc : [el, ...acc]), []);
// EXAMPLES
takeRightWhile([1, 2, 3, 4], n => n < 3); // [3, 4]
根据特定条件,过滤某一个数组
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));
};
// EXAMPLES
var myArray = [{ x: 1 }, { x: 2 }, { x: 3 }, { x: 1 }];
pullBy(myArray, [{ x: 1 }, { x: 3 }], o => o.x); // myArray = [{ x: 2 }]
深度展开数组,不是克隆哦,还会存在引用的情况
const deepFlatten = arr => [].concat(...arr.map(v => (Array.isArray(v) ? deepFlatten(v) : v)));
// EXAMPLES
deepFlatten([1, [2], [[3], 4], 5]); // [1,2,3,4,5]
多维数组,展开至只有一层
const flatten = (arr, depth = 1) =>
arr.reduce((a, v) => a.concat(depth > 1 && Array.isArray(v) ? flatten(v, depth - 1) : v), []);
EXAMPLES
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]
从数组末尾删除元素,直到传递的函数返回true。返回数组中剩余的元素。
const dropRightWhile = (arr, func) => {
let rightIndex = arr.length;
while (rightIndex-- && !func(arr[rightIndex]));
return arr.slice(0, rightIndex + 1);
};
// EXAMPLES
dropRightWhile([1, 2, 3, 4], n => n < 3); // [1, 2]
删除数组中的元素,直到传递的函数返回true。返回移除的元素。
const takeWhile = (arr, func) => {
for (const [i, val] of arr.entries()) if (func(val)) return arr.slice(0, i);
return arr;
};
// EXAMPLES
takeWhile([1, 2, 3, 4], n => n >= 3); // [1, 2]
初始化某个数组
const initializeArrayWithRange = (end, start = 0, step = 1) =>
Array.from({ length: Math.ceil((end - start + 1) / step) }, (v, i) => i * step + start);
// EXAMPLES
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]
倒叙初始化某个数组
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
);
EXAMPLES
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]
根据特定条件,从数组中选出相同的放在一个数组,不同的放在另一个数组
const bifurcateBy = (arr, fn) =>
arr.reduce((acc, val, i) => (acc[fn(val, i) ? 0 : 1].push(val), acc), [[], []]);
// EXAMPLES
bifurcateBy(['beep', 'boop', 'foo', 'bar'], x => x[0] === 'b'); // [ ['beep', 'boop', 'bar'], ['foo'] ]
返回两个数组中都存在的值
const intersection = (a, b) => {
const s = new Set(b);
return a.filter(x => s.has(x));
};
// EXAMPLES
intersection([1, 2, 3], [4, 3, 2]); // [2, 3]
返回两个数组中都没有的值,不会去重哦
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))];
};
// EXAMPLES
symmetricDifference([1, 2, 3], [1, 2, 4]); // [3, 4]
symmetricDifference([1, 2, 2], [1, 3, 1]); // [2, 2, 3]
返回两个数组中都没有的值,会去重
const uniqueSymmetricDifference = (a, b) => [
...new Set([...a.filter(v => !b.includes(v)), ...b.filter(v => !a.includes(v))])
];
// EXAMPLES
uniqueSymmetricDifference([1, 2, 3], [1, 2, 4]); // [3, 4]
uniqueSymmetricDifference([1, 2, 2], [1, 3, 1]); // [2, 3]
返回同时出现在两个数组中的元素的数组。
const similarity = (arr, values) => arr.filter(v => values.includes(v));
EXAMPLES
similarity([1, 2, 3], [1, 2, 4]); // [1, 2]
特定条件数组过滤
const reject = (pred, array) => array.filter((...args) => !pred(...args));
// EXAMPLES
reject(x => x % 2 === 0, [1, 2, 3, 4, 5]); // [1, 3, 5]
reject(word => word.length > 4, ['Apple', 'Pear', 'Kiwi', 'Banana']); // ['Pear', 'Kiwi']
计算数组中某个值的出现次数
const countOccurrences = (arr, val) => arr.reduce((a, v) => (v === val ? a + 1 : a), 0);
// EXAMPLES
countOccurrences([1, 1, 2, 1, 2, 3], 1); // 3
查找当前值,在数组中的所有下标位置,没有返回空数组
const indexOfAll = (arr, val) => arr.reduce((acc, el, i) => (el === val ? [...acc, i] : acc), []);
// EXAMPLES
indexOfAll([1, 2, 3, 1, 2, 3], 1); // [0,3]
indexOfAll([1, 2, 3], 4); // []
数组过滤
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));
};
// EXAMPLES
let myArray = ['a', 'b', 'c', 'a', 'b', 'c'];
pull(myArray, 'a', 'c'); // myArray = [ 'b', 'b' ]
特定下标数组过滤
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;
};
// EXAMPLES
let myArray = ['a', 'b', 'c', 'd'];
let pulled = pullAtIndex(myArray, [1, 3]); // myArray = [ 'a', 'c' ] , pulled = [ 'b', 'd' ]
判断某数组里面的所有值,是否在另一个数组里面
const includesAll = (arr, values) => values.every(v => arr.includes(v));
// EXAMPLES
includesAll([1, 2, 3, 4], [1, 4]); // true
includesAll([1, 2, 3, 4], [1, 5]); // false
判断某数组里面的某一个值,是否在另一个数组里面
const includesAny = (arr, values) => values.some(v => arr.includes(v));
// EXAMPLES
includesAny([1, 2, 3, 4], [2, 9]); // true
includesAny([1, 2, 3, 4], [8, 9]); // false
数值初始化
const initializeArrayWithValues = (n, val = 0) => Array(n).fill(val);
EXAMPLES
initializeArrayWithValues(5, 2); // [2, 2, 2, 2, 2]
判断数组是升序还是降序或者是别的,升序1,降序-1,其他0
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;
}
};
EXAMPLES
isSorted([0, 1, 2, 2]); // 1
isSorted([4, 3, 2]); // -1
isSorted([4, 3, 5]); // 0
date 相关的
日期格式化
const formatDuration = ms => {
if (ms < 0) ms = -ms;
const time = {
day: Math.floor(ms / 86400000),
hour: Math.floor(ms / 3600000) % 24,
minute: Math.floor(ms / 60000) % 60,
second: Math.floor(ms / 1000) % 60,
millisecond: Math.floor(ms) % 1000
};
return Object.entries(time)
.filter(val => val[1] !== 0)
.map(([key, val]) => `${val} ${key}${val !== 1 ? 's' : ''}`)
.join(', ');
};
EXAMPLES
formatDuration(1001); // '1 second, 1 millisecond'
formatDuration(34325055574); // '397 days, 6 hours, 44 minutes, 15 seconds, 574 milliseconds'
两个日期的差值
const getDaysDiffBetweenDates = (dateInitial, dateFinal) =>
(dateFinal - dateInitial) / (1000 * 3600 * 24);
EXAMPLES
getDaysDiffBetweenDates(new Date('2017-12-13'), new Date('2017-12-22')); // 9
brower 相关的
强制从http跳转到https
const httpsRedirect = () => {
if (location.protocol !== 'https:') location.replace('https://' + location.href.split('//')[1]);
};
EXAMPLES
httpsRedirect(); // If you are on http://mydomain.com, you are redirected to https://mydomain.com
判断某个元素里面是否有某一个 css class
const hasClass = (el, className) => el.classList.contains(className);
EXAMPLES
hasClass(document.querySelector('p.special'), 'special'); // true
判断是pc还是移动端
const detectDeviceType = () =>
/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent)
? 'Mobile'
: 'Desktop';
EXAMPLES
detectDeviceType(); // "Mobile" or "Desktop"