Lenny-Hu / note

blog
5 stars 1 forks source link

JavaScript 数组操作常用代码 #15

Open Lenny-Hu opened 5 years ago

Lenny-Hu commented 5 years ago

检测数组所有元素是否都符合指定条件(提供函数,不提供时,默认使用Boolean)

const all = (arr, fn = Boolean) => arr.every(fn);
all([4, 2, 3], x => x > 1); // true
all([1, 2, 3]); // true
// 不传fn时,执行过程为 Boolean(currentValue),currentValue为数组的每一项元素,即1, 2, 3, 0,Boolean(0) 返回false,所以该函数整体返回false
all([1, 2, 3, 0]); // false

var array1 = [1, 30, 39, 29, 10, 13];

console.log(array1.every(isBelowThreshold)); // expected output: true

Lenny-Hu commented 5 years ago

检查数组所有的元素是否相等

const allEqual = arr => arr.every(val => val === arr[0]);
allEqual([1, 2, 3, 4, 5, 6]); // false
allEqual([1, 1, 1, 1]); // true
Lenny-Hu commented 5 years ago

检查数组元素是否有一项满足给定的条件(提供函数,不提供使用Boolean进行求值)

const any = (arr, fn = Boolean) => arr.some(fn);
any([0, 1, 2, 0], x => x >= 2); // true
any([0, 0, 1, 0]); // true
any([0, 0, 0, 0]); // false

var even = function(element) { // checks whether an element is even return element % 2 === 0; };

console.log(array.some(even)); // expected output: true

Lenny-Hu commented 5 years ago

将二维数组输出为csv格式字符串

const arrayToCSV = (arr, delimiter = ',') =>
  arr
    .map(v => v.map(x => (isNaN(x) ? `"${String(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'
arrayToCSV([['a,', 'b'], ['c', 'd']]); // ""a,","b" \n "c","d""

arrayToCSV([[NaN, 'a', 'b'], ['c', 'd']]); // ""NaN","a","b" \n "c","d""
arrayToCSV([[{}, 'a', 'b'], ['c', 'd']]); // ""[object Object]","a","b" \n "c","d""

判断值能否转换为数字,如果不可以,则在该值两侧加""(两侧添加双引号处理值内部有,号的情况)或者在值内部有双引号的地方再添加一个双引号进行转义;最终让文件能被excel正常打开 isNaN运算实际过程是这样的: isNaN(Number(item))

// pass a function to map const map1 = array1.map(x => x * 2);

console.log(map1); // expected output: Array [2, 8, 18, 32]

Lenny-Hu commented 5 years ago

根据条件(布尔值数组),将数组分隔成一个长度为2的二维数组,数组元素运算结果为true的在前面,否则在后面

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'] ]

// 1 + 2 + 3 + 4 console.log(array1.reduce(reducer)); // expected output: 10

// 5 + 1 + 2 + 3 + 4 console.log(array1.reduce(reducer, 5)); // expected output: 15

Lenny-Hu commented 5 years ago

根据条件(函数),将数组分隔成一个长度为2的二维数组,数组元素运算结果为true的在前面,否则在后面

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'] ]
Lenny-Hu commented 5 years ago

将一维数组分割成指定二维长度(最大)的二维数组

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]]

Array.from([1, 2, 3], x => x + x); // 这个类似 map 方法 // x => x + x代表这是一个函数,只是省略了其他的定义,这是一种Lambda表达式的写法 // 箭头的意思表示从当前数组中取出一个值,然后自加,并将返回的结果添加到新数组中
// [2, 4, 6]

// 创建长度为5的数组,每一项值为 index 的值 Array.from({length: 5}, (v, i) => i); // [0, 1, 2, 3, 4]

// 数组去重合并 Array.from(new Set([1, 2, 3].cocncat([1, 2, 3, 4]))) // [1, 2, 3, 4]

Lenny-Hu commented 5 years ago

删除数组中运算结果为false的值 (false, null, 0, "", undefined, and 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 ]

// 第二个写法
const filterFalsy = arr => arr.filter(Boolean);
filterFalsy(['', true, {}, false, 'sample', 1, 0]); // [true, {}, 'sample', 1]

const result = words.filter(word => word.length > 6);

console.log(result); // expected output: Array ["exuberant", "destruction", "present"]

Lenny-Hu commented 5 years ago

根据给定函数对数组的元素运算得到新数组,然后返回新数组中的各元素的数量

const countBy = (arr, fn) =>
  arr.map(typeof fn === 'function' ? fn : val => val[fn]).reduce((acc, val) => {
    acc[val] = (acc[val] || 0) + 1;
    return acc;
  }, {});

// Math.floor 对元素进行 四舍五入 得到新数组 [6, 4, 6], 然后得到统计结果,即 4 有一个,6有2个
countBy([6.1, 4.2, 6.3], Math.floor); // {4: 1, 6: 2}

// 传 length 参数代表读取每一项元素的长度, 所以map后的新数组为 [3, 3, 5],统计结果为长度为3的元素有2个,长度为5的元素有1个
countBy(['one', 'two', 'three'], 'length'); // {3: 2, 5: 1}

// 按元素首字符统计结果,即 o 开头的有1个,t开头的有2个
countBy(['one', 'two', 'three'], 0); // {o: 1, t: 2}
Lenny-Hu commented 5 years ago

统计数组中指定值出现的次数

const countOccurrences = (arr, val) => arr.reduce((a, v) => (v === val ? a + 1 : a), 0);

countOccurrences([1, 1, 1, 2], 1) // 3
Lenny-Hu commented 5 years ago

使用递归将多维数组扁平化为一维数组

const deepFlatten = arr => [].concat(...arr.map(v => (Array.isArray(v) ? deepFlatten(v) : v)));

deepFlatten([1, [2], [[3], 4], 5]); // [1,2,3,4,5]

deepFlatten([1, [2, [3]]]) // [1, 2, 3]
Lenny-Hu commented 5 years ago

返回两个数组之间的差异(给定数组a和b,返回一个新数组,仅包含数组a与数组b对比,数组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]
difference([1, 2, 3], [1, 2, 3, 4, 5, 6]); // []
Lenny-Hu commented 5 years ago

根据提供的函数应用于两个数组的每个数组元素后,返回两个数组之间的差异(给定数组a和b以及一个map中使用的函数,返回一个新数组,仅包含数组a与数组b对比,数组b中没有那些的值)

const differenceBy = (a, b, fn) => {
  const s = new Set(b.map(fn));
  return a.map(fn).filter(el => !s.has(el));
};

// Math.floor 四色五入后,是 [2, 1] 与 [2, 3] 对比,后者中没有 1, 所以结果 为 [1]
differenceBy([2.1, 1.2], [2.3, 3.4], Math.floor); // [1]
// map 后进行对比的两个数组是 [2, 1] 与 [1], 后者中没有 2, 所以结果为 [2]
differenceBy([{ x: 2 }, { x: 1 }], [{ x: 1 }], v => v.x); // [2]
Lenny-Hu commented 5 years ago

使用自定义的比较方法,找出两个数组的差异值

const differenceWith = (arr, val, comp) => arr.filter(a => val.findIndex(b => comp(a, b)) === -1);

// 两个数组在Math.round方法处理后为 [1, 1, 2, 3, 0] 和 [2, 3, 0],第一个数组中的前两项符合对比方法(当在数组val中找不到1的时候,findIndex方法返回-1),所以filter的结果为[1, 1.2]
differenceWith([1, 1.2, 1.5, 3, 0], [1.9, 3, 0], (a, b) => Math.round(a) === Math.round(b)); // [1, 1.2]

function isLargeNumber(element) { return element > 13; }

console.log(array1.findIndex(isLargeNumber)); // expected output: 3

Lenny-Hu commented 5 years ago

返回一个从左侧移除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], 42); // []
Lenny-Hu commented 5 years ago

返回一个从右边移除n个元素的新数组

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); // []
Lenny-Hu commented 5 years ago

从数组末尾移除元素,直到传递的函数返回true为止。返回数组中的其余元素

const dropRightWhile = (arr, func) => {
  while (arr.length > 0 && !func(arr[arr.length - 1])) arr = arr.slice(0, -1);
  return arr;
};

dropRightWhile([1, 2, 3, 4], n => n < 3); // [1, 2]
Lenny-Hu commented 5 years ago

移除数组中的元素,直到传递的函数返回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]
Lenny-Hu commented 5 years ago

根据提供的间隔数从数组挑选出元素

const everyNth = (arr, nth) => arr.filter((e, i) => i % nth === nth - 1);

// 每间隔1个挑出来
everyNth([1, 2, 3, 4, 5, 6], 2); // [ 2, 4, 6 ]

// 每间隔3个挑出来
everyNth([1, 2, 3, 4, 5, 6], 4); // [ 4 ]
Lenny-Hu commented 5 years ago

返回数组中只出现一次的值(过滤掉出现2次及以上的值)

const filterNonUnique = arr => arr.filter(i => arr.indexOf(i) === arr.lastIndexOf(i));

filterNonUnique([1, 2, 2, 3, 4, 4, 5]); // [1, 3, 5]
filterNonUnique([1, 2, 2, 2, 4, 4, 5]); // [1, 5]
Lenny-Hu commented 5 years ago

根据提供的比较器函数过滤数组中的非惟一值(保留唯一值)

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' } ]
Lenny-Hu commented 5 years ago

返回条件函数通过filter过滤后的数组的最后一个值

const findLast = (arr, fn) => arr.filter(fn).pop();
findLast([1, 2, 3, 4], n => n % 2 === 1); // 3
Lenny-Hu commented 5 years ago

返回条件函数通过filter过滤后的数组的最后一个值在原始数组中的索引

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)
Lenny-Hu commented 5 years ago

将多维数组扁平化指定层级(非扁平化到指定层级)

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]
flatten([1, [2, [3, [4, 5], 6], 7], 8], 1); // [1, 2, [3, [4, 5], 6], 7, 8]
Lenny-Hu commented 5 years ago

从尾到头开始遍历数组

const forEachRight = (arr, callback) =>
  arr
    .slice(0)
    .reverse()
    .forEach(callback);

forEachRight([1, 2, 3, 4], val => console.log(val)); // '4', '3', '2', '1'
Lenny-Hu commented 5 years ago

根据给定的函数对数组的元素进行分组,返回一个对象

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']}