1. all:布尔全等判断

  1. const all = (arr, fn = Boolean) => arr.every(fn);
  2. all([4, 2, 3], x => x > 1); // true
  3. all([1, 2, 3]); // true

2. allEqual:检查数组各项相等

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

3. approximatelyEqual:约等于

  1. const approximatelyEqual = (v1, v2, epsilon = 0.001) => Math.abs(v1 - v2) < epsilon;
  2. approximatelyEqual(Math.PI / 2.0, 1.5708); // true

4. arrayToCSV:数组转CSV格式(带空格的字符串)

  1. const arrayToCSV = (arr, delimiter = ',') =>
  2. arr.map(v => v.map(x => `"${x}"`).join(delimiter)).join('\n');
  3. arrayToCSV([['a', 'b'], ['c', 'd']]); // '"a","b"\n"c","d"'
  4. arrayToCSV([['a', 'b'], ['c', 'd']], ';'); // '"a";"b"\n"c";"d"'

6. average:平均数

  1. const average = (...nums) => nums.reduce((acc, val) => acc + val, 0) / nums.length;
  2. average(...[1, 2, 3]); // 2
  3. average(1, 2, 3); // 2

7. averageBy:数组对象属性平均数

此代码段将获取数组对象属性的平均值

  1. 1. const averageBy = (arr, fn) =>
  2. 2. arr.map(typeof fn === 'function' ? fn : val => val[fn]).reduce((acc, val) => acc + val, 0) /
  3. 3. arr.length;
  4. 4.
  5. 5. averageBy([{ n: 4 }, { n: 2 }, { n: 8 }, { n: 6 }], o => o.n); // 5
  6. 6. averageBy([{ n: 4 }, { n: 2 }, { n: 8 }, { n: 6 }], 'n'); // 5
  7. 7. 复制代码

8. bifurcate:拆分断言后的数组

可以根据每个元素返回的值,使用reduce()push() 将元素添加到第二次参数fn中 。

  1. 1. const bifurcate = (arr, filter) =>
  2. 2. arr.reduce((acc, val, i) => (acc[filter[i] ? 0 : 1].push(val), acc), [[], []]);
  3. 3. bifurcate(['beep', 'boop', 'foo', 'bar'], [true, true, false, true]);
  4. 4. // [ ['beep', 'boop', 'bar'], ['foo'] ]
  5. 5. 复制代码

9. castArray:其它类型转数组

  1. 1. const castArray = val => (Array.isArray(val) ? val : [val]);
  2. 2.
  3. 3. castArray('foo'); // ['foo']
  4. 4. castArray([1]); // [1]
  5. 5. castArray(1); // [1]
  6. 6. 复制代码

10. compact:去除数组中的无效/无用值

  1. const compact = arr => arr.filter(Boolean);
  2. compact([0, 1, false, 2, '', 3, 'a', 'e' * 23, NaN, 's', 34]);
  3. // [ 1, 2, 3, 'a', 's', 34 ]

11. countOccurrences:检测数值出现次数

  1. const countOccurrences = (arr, val) => arr.reduce((a, v) => (v === val ? a + 1 : a), 0);
  2. countOccurrences([1, 1, 2, 1, 2, 3], 1); // 3

12. deepFlatten:递归扁平化数组

  1. const deepFlatten = arr => [].concat(...arr.map(v => (Array.isArray(v) ? deepFlatten(v) : v)));
  2. deepFlatten([1, [2], [[3], 4], 5]); // [1,2,3,4,5]

13. difference:寻找差异(并返回第一个数组独有的)

此代码段查找两个数组之间的差异,并返回第一个数组独有的。

  1. const difference = (a, b) => {
  2. const s = new Set(b);
  3. return a.filter(x => !s.has(x));
  4. };
  5. difference([1, 2, 3], [1, 2, 4]); // [3]

14. differenceBy:先执行再寻找差异

在将给定函数应用于两个列表的每个元素之后,此方法返回两个数组之间的差异。

  1. 1. const differenceBy = (a, b, fn) => {
  2. 2. const s = new Set(b.map(fn));
  3. 3. return a.filter(x => !s.has(fn(x)));
  4. 4. };
  5. 5.
  6. 6. differenceBy([2.1, 1.2], [2.3, 3.4], Math.floor); // [1.2]
  7. 7. differenceBy([{ x: 2 }, { x: 1 }], [{ x: 1 }], v => v.x); // [ { x: 2 } ]
  8. 8. 复制代码

15. dropWhile:删除不符合条件的值

此代码段从数组顶部开始删除元素,直到传递的函数返回为true

  1. const dropWhile = (arr, func) => {
  2. while (arr.length > 0 && !func(arr[0])) arr = arr.slice(1);
  3. return arr;
  4. };
  5. dropWhile([1, 2, 3, 4], n => n >= 3); // [3,4]

16. flatten:指定深度扁平化数组

此代码段第二参数可指定深度。

  1. const flatten = (arr, depth = 1) =>
  2. arr.reduce((a, v) => a.concat(depth > 1 && Array.isArray(v) ? flatten(v, depth - 1) : v), []);
  3. flatten([1, [2], 3, 4]); // [1, 2, 3, 4]
  4. flatten([1, [2, [3, [4, 5], 6], 7], 8], 2); // [1, 2, 3, [4, 5], 6, 7, 8]

17. indexOfAll:返回数组中某值的所有索引

此代码段可用于获取数组中某个值的所有索引,如果此值中未包含该值,则返回一个空数组。

  1. 1. const indexOfAll = (arr, val) => arr.reduce((acc, el, i) => (el === val ? [...acc, i] : acc), []);
  2. 2.
  3. 3. indexOfAll([1, 2, 3, 1, 2, 3], 1); // [0,3]
  4. 4. indexOfAll([1, 2, 3], 4); // []
  5. 5. 复制代码

18. intersection:两数组的交集

  1. 1.
  2. 2. const intersection = (a, b) => {
  3. 3. const s = new Set(b);
  4. 4. return a.filter(x => s.has(x));
  5. 5. };
  6. 6.
  7. 7. intersection([1, 2, 3], [4, 3, 2]); // [2, 3]
  8. 8. 复制代码

19. intersectionWith:两数组都符合条件的交集

此片段可用于在对两个数组的每个元素执行了函数之后,返回两个数组中存在的元素列表。

  1. 1.
  2. 2. const intersectionBy = (a, b, fn) => {
  3. 3. const s = new Set(b.map(fn));
  4. 4. return a.filter(x => s.has(fn(x)));
  5. 5. };
  6. 6.
  7. 7. intersectionBy([2.1, 1.2], [2.3, 3.4], Math.floor); // [2.1]
  8. 8. 复制代码

20. intersectionWith:先比较后返回交集

  1. 1. const intersectionWith = (a, b, comp) => a.filter(x => b.findIndex(y => comp(x, y)) !== -1);
  2. 2.
  3. 3. 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]
  4. 4. 复制代码

21. minN:返回指定长度的升序数组

  1. const minN = (arr, n = 1) => [...arr].sort((a, b) => a - b).slice(0, n);
  2. minN([1, 2, 3]); // [1]
  3. minN([1, 2, 3], 2); // [1,2]

22. negate:根据条件反向筛选

  1. const negate = func => (...args) => !func(...args);
  2. [1, 2, 3, 4, 5, 6].filter(negate(n => n % 2 === 0)); // [ 1, 3, 5 ]

23. randomIntArrayInRange:生成两数之间指定长度的随机数组

  1. const randomIntArrayInRange = (min, max, n = 1) =>
  2. Array.from({ length: n }, () => Math.floor(Math.random() * (max - min + 1)) + min);
  3. randomIntArrayInRange(12, 35, 10); // [ 34, 14, 27, 17, 30, 27, 20, 26, 21, 14 ]

24. sample:在指定数组中获取随机数

  1. const sample = arr => arr[Math.floor(Math.random() * arr.length)];
  2. sample([3, 7, 9, 11]); // 9

25. sampleSize:在指定数组中获取指定长度的随机数

此代码段可用于从数组中获取指定长度的随机数,直至穷尽数组。 使用**Fisher-Yates**算法对数组中的元素进行随机选择。

  1. const sampleSize = ([...arr], n = 1) => {
  2. let m = arr.length;
  3. while (m) {
  4. const i = Math.floor(Math.random() * m--);
  5. [arr[m], arr[i]] = [arr[i], arr[m]];
  6. }
  7. return arr.slice(0, n);
  8. };
  9. sampleSize([1, 2, 3], 2); // [3,1]
  10. sampleSize([1, 2, 3], 4); // [2,3,1]

26. shuffle:“洗牌” 数组

此代码段使用Fisher-Yates算法随机排序数组的元素。

  1. const shuffle = ([...arr]) => {
  2. let m = arr.length;
  3. while (m) {
  4. const i = Math.floor(Math.random() * m--);
  5. [arr[m], arr[i]] = [arr[i], arr[m]];
  6. }
  7. return arr;
  8. };
  9. const foo = [1, 2, 3];
  10. shuffle(foo); // [2, 3, 1], foo = [1, 2, 3]

27. nest:根据parent_id生成树结构(阿里一面真题)

根据每项的parent_id,生成具体树形结构的对象。

  1. const nest = (items, id = null, link = 'parent_id') => items.filter(item => item[link] === id)
  2. .map(item => ({ ...item, children: nest(items, item.id) }));

用法:

  1. const comments = [
  2. { id: 1, parent_id: null },
  3. { id: 2, parent_id: 1 },
  4. { id: 3, parent_id: 1 },
  5. { id: 4, parent_id: 2 },
  6. { id: 5, parent_id: 4 }
  7. ];
  8. const nestedComments = nest(comments); // [{ id: 1, parent_id: null, children: [...] }]


数组操作 - 图1

强烈建议去理解这个的实现,因为这是我亲身遇到的阿里一面真题:

28.数组去重的12种方法

  1. 数组去重,一般都是在面试的时候才会碰到,一般是要求手写数组去重方法的代码。如果是被提问到,数组去重的方法有哪些?你能答出其中的10种,面试官很有可能对你刮目相看。
  2. 在真实的项目中碰到的数组去重,一般都是后台去处理,很少让前端处理数组去重。虽然日常项目用到的概率比较低,但还是需要了解一下,以防面试的时候可能回被问到。
  3. 注:写的匆忙,加上这几天有点忙,还没有非常认真核对过,不过思路是没有问题,可能一些小细节出错而已。
  4. 数组去重的方法
  5. 一、利用ES6 Set去重(ES6中最常用)
  6. function unique (arr) {
  7. return Array.from(new Set(arr))
  8. }
  9. var arr = [1,1,'true','true',true,true,15,15,false,false, undefined,undefined, null,null, NaN, NaN,'NaN', 0, 0, 'a', 'a',{},{}];
  10. console.log(unique(arr))
  11. //[1, "true", true, 15, false, undefined, null, NaN, "NaN", 0, "a", {}, {}]
  12. 不考虑兼容性,这种去重的方法代码最少。这种方法还无法去掉“{}”空对象,后面的高阶方法会添加去掉重复“{}”的方法。
  13. 二、利用for嵌套for,然后splice去重(ES5中最常用)
  14. function unique(arr){
  15. for(var i=0; i<arr.length; i++){
  16. for(var j=i+1; j<arr.length; j++){
  17. if(arr[i]==arr[j]){ //第一个等同于第二个,splice方法删除第二个
  18. arr.splice(j,1);
  19. j--;
  20. }
  21. }
  22. }
  23. return arr;
  24. }
  25. var arr = [1,1,'true','true',true,true,15,15,false,false, undefined,undefined, null,null, NaN, NaN,'NaN', 0, 0, 'a', 'a',{},{}];
  26. console.log(unique(arr))
  27. //[1, "true", 15, false, undefined, NaN, NaN, "NaN", "a", {…}, {…}] //NaN和{}没有去重,两个null直接消失了
  28. 双层循环,外层循环元素,内层循环时比较值。值相同时,则删去这个值。
  29. 想快速学习更多常用的ES6语法,可以看我之前的文章《学习ES6笔记──工作中常用到的ES6语法》。
  30. 三、利用indexOf去重
  31. function unique(arr) {
  32. if (!Array.isArray(arr)) {
  33. console.log('type error!')
  34. return
  35. }
  36. var array = [];
  37. for (var i = 0; i < arr.length; i++) {
  38. if (array .indexOf(arr[i]) === -1) {
  39. array .push(arr[i])
  40. }
  41. }
  42. return array;
  43. }
  44. var arr = [1,1,'true','true',true,true,15,15,false,false, undefined,undefined, null,null, NaN, NaN,'NaN', 0, 0, 'a', 'a',{},{}];
  45. console.log(unique(arr))
  46. // [1, "true", true, 15, false, undefined, null, NaN, NaN, "NaN", 0, "a", {…}, {…}] //NaN、{}没有去重
  47. 新建一个空的结果数组,for 循环原数组,判断结果数组是否存在当前元素,如果有相同的值则跳过,不相同则push进数组。
  48. 四、利用sort()
  49. function unique(arr) {
  50. if (!Array.isArray(arr)) {
  51. console.log('type error!')
  52. return;
  53. }
  54. arr = arr.sort()
  55. var arrry= [arr[0]];
  56. for (var i = 1; i < arr.length; i++) {
  57. if (arr[i] !== arr[i-1]) {
  58. arrry.push(arr[i]);
  59. }
  60. }
  61. return arrry;
  62. }
  63. var arr = [1,1,'true','true',true,true,15,15,false,false, undefined,undefined, null,null, NaN, NaN,'NaN', 0, 0, 'a', 'a',{},{}];
  64. console.log(unique(arr))
  65. // [0, 1, 15, "NaN", NaN, NaN, {…}, {…}, "a", false, null, true, "true", undefined] //NaN、{}没有去重
  66. 利用sort()排序方法,然后根据排序后的结果进行遍历及相邻元素比对。
  67. 五、利用对象的属性不能相同的特点进行去重(这种数组去重的方法有问题,不建议用,有待改进)
  68. function unique(arr) {
  69. if (!Array.isArray(arr)) {
  70. console.log('type error!')
  71. return
  72. }
  73. var arrry= [];
  74. var obj = {};
  75. for (var i = 0; i < arr.length; i++) {
  76. if (!obj[arr[i]]) {
  77. arrry.push(arr[i])
  78. obj[arr[i]] = 1
  79. } else {
  80. obj[arr[i]]++
  81. }
  82. }
  83. return arrry;
  84. }
  85. var arr = [1,1,'true','true',true,true,15,15,false,false, undefined,undefined, null,null, NaN, NaN,'NaN', 0, 0, 'a', 'a',{},{}];
  86. console.log(unique(arr))
  87. //[1, "true", 15, false, undefined, null, NaN, 0, "a", {…}] //两个true直接去掉了,NaN和{}去重
  88. 六、利用includes
  89. function unique(arr) {
  90. if (!Array.isArray(arr)) {
  91. console.log('type error!')
  92. return
  93. }
  94. var array =[];
  95. for(var i = 0; i < arr.length; i++) {
  96. if( !array.includes( arr[i]) ) {//includes 检测数组是否有某个值
  97. array.push(arr[i]);
  98. }
  99. }
  100. return array
  101. }
  102. var arr = [1,1,'true','true',true,true,15,15,false,false, undefined,undefined, null,null, NaN, NaN,'NaN', 0, 0, 'a', 'a',{},{}];
  103. console.log(unique(arr))
  104. //[1, "true", true, 15, false, undefined, null, NaN, "NaN", 0, "a", {…}, {…}] //{}没有去重
  105. 七、利用hasOwnProperty
  106. function unique(arr) {
  107. var obj = {};
  108. return arr.filter(function(item, index, arr){
  109. return obj.hasOwnProperty(typeof item + item) ? false : (obj[typeof item + item] = true)
  110. })
  111. }
  112. var arr = [1,1,'true','true',true,true,15,15,false,false, undefined,undefined, null,null, NaN, NaN,'NaN', 0, 0, 'a', 'a',{},{}];
  113. console.log(unique(arr))
  114. //[1, "true", true, 15, false, undefined, null, NaN, "NaN", 0, "a", {…}] //所有的都去重了
  115. 利用hasOwnProperty 判断是否存在对象属性
  116. 八、利用filter
  117. function unique(arr) {
  118. return arr.filter(function(item, index, arr) {
  119. //当前元素,在原始数组中的第一个索引==当前索引值,否则返回当前元素
  120. return arr.indexOf(item, 0) === index;
  121. });
  122. }
  123. var arr = [1,1,'true','true',true,true,15,15,false,false, undefined,undefined, null,null, NaN, NaN,'NaN', 0, 0, 'a', 'a',{},{}];
  124. console.log(unique(arr))
  125. //[1, "true", true, 15, false, undefined, null, "NaN", 0, "a", {…}, {…}]
  126. 九、利用递归去重
  127. function unique(arr) {
  128. var array= arr;
  129. var len = array.length;
  130. array.sort(function(a,b){ //排序后更加方便去重
  131. return a - b;
  132. })
  133. function loop(index){
  134. if(index >= 1){
  135. if(array[index] === array[index-1]){
  136. array.splice(index,1);
  137. }
  138. loop(index - 1); //递归loop,然后数组去重
  139. }
  140. }
  141. loop(len-1);
  142. return array;
  143. }
  144. var arr = [1,1,'true','true',true,true,15,15,false,false, undefined,undefined, null,null, NaN, NaN,'NaN', 0, 0, 'a', 'a',{},{}];
  145. console.log(unique(arr))
  146. //[1, "a", "true", true, 15, false, 1, {…}, null, NaN, NaN, "NaN", 0, "a", {…}, undefined]
  147. 十、利用Map数据结构去重
  148. function arrayNonRepeatfy(arr) {
  149. let map = new Map();
  150. let array = new Array(); // 数组用于返回结果
  151. for (let i = 0; i < arr.length; i++) {
  152. if(map .has(arr[i])) { // 如果有该key值
  153. map .set(arr[i], true);
  154. } else {
  155. map .set(arr[i], false); // 如果没有该key值
  156. array .push(arr[i]);
  157. }
  158. }
  159. return array ;
  160. }
  161. var arr = [1,1,'true','true',true,true,15,15,false,false, undefined,undefined, null,null, NaN, NaN,'NaN', 0, 0, 'a', 'a',{},{}];
  162. console.log(unique(arr))
  163. //[1, "a", "true", true, 15, false, 1, {…}, null, NaN, NaN, "NaN", 0, "a", {…}, undefined]
  164. 创建一个空Map数据结构,遍历需要去重的数组,把数组的每一个元素作为key存到Map中。由于Map中不会出现相同的key值,所以最终得到的就是去重后的结果。
  165. 十一、利用reduce+includes
  166. function unique(arr){
  167. return arr.reduce((prev,cur) => prev.includes(cur) ? prev : [...prev,cur],[]);
  168. }
  169. var arr = [1,1,'true','true',true,true,15,15,false,false, undefined,undefined, null,null, NaN, NaN,'NaN', 0, 0, 'a', 'a',{},{}];
  170. console.log(unique(arr));
  171. // [1, "true", true, 15, false, undefined, null, NaN, "NaN", 0, "a", {…}, {…}]
  172. 十二、[...new Set(arr)]
  173. [...new Set(arr)]
  174. //代码就是这么少----(其实,严格来说并不算是一种,相对于第一种方法来说只是简化了代码)
  175. function distinct(a, b) {
  176. return Array.from(new Set([...a, ...b]))
  177. }
  178. PS:有些文章提到了foreach+indexOf数组去重的方法,个人觉得都是大同小异,所以没有写上去。

29.找到最接近的数

根据一个值,从数组中查找与之最接近的值
首先把这个值插入数组,然后执行排序,接着与之前后两个数进行差值计算,返回与之最接近的值

  1. /**
  2. * @description: 从数组中找到最接近的数
  3. * @param {Number} val
  4. * @param {Array} data
  5. * @return {Number} 最接近当前值的结果
  6. * @author: wangchaoxu
  7. */
  8. function findNearByArr(val, data) {
  9. if (!!~data.indexOf(val)) return val;
  10. data.push(val);
  11. let newArr = data.sort((a, b) => a - b);
  12. let pre = newArr[newArr.indexOf(val) - 1];
  13. let next = newArr[newArr.indexOf(val) + 1];
  14. return val - pre > next - val || val - pre === next - val ? next : pre;
  15. }
  16. console.log(findNearByArr(1, [0.1,-1,-0.5,5,6,7,9,2]));//0.1

30.扁平化

  • 需求

    1. let ary = [1, [2, [3, [4, 5]]], 6];
    2. let str = JSON.stringify(ary);
  • 第0种处理:直接的调用

    1. arr_flat = arr.flat(Infinity);
  • 第一种处理

    1. ary = str.replace(/(\[\]))/g, '').split(',');
  • 第二种处理

    1. str = str.replace(/(\[\]))/g, '');
    2. str = '[' + str + ']';
    3. ary = JSON.parse(str);
  • 第三种处理:递归处理

    1. let result = [];
    2. let fn = function(ary) {
    3. for(let i = 0; i < ary.length; i++) }{
    4. let item = ary[i];
    5. if (Array.isArray(ary[i])){
    6. fn(item);
    7. } else {
    8. result.push(item);
    9. }
    10. }
    11. }
  • 第四种处理:用 reduce 实现数组的 flat 方法

    1. function flatten(ary) {
    2. return ary.reduce((pre, cur) => {
    3. return pre.concat(Array.isArray(cur) ? flatten(cur) : cur);
    4. })
    5. }
    6. let ary = [1, 2, [3, 4], [5, [6, 7]]]
    7. console.log(ary.MyFlat(Infinity))
  • 第五种处理:扩展运算符

    1. while (ary.some(Array.isArray)) {
    2. ary = [].concat(...ary);
    3. }
  • 第六处理多维 ```javascript const arr1 = [1, 2, [3, 4]]; arr1.flat(); // [1, 2, 3, 4]

const arr2 = [1, 2, [3, 4, [5, 6]]]; arr2.flat(); // [1, 2, 3, 4, [5, 6]]

const arr3 = [1, 2, [3, 4, [5, 6]]]; arr3.flat(2); // [1, 2, 3, 4, 5, 6]

const arr4 = [1, 2, [3, 4, [5, 6, [7, 8, [9, 10]]]]]; arr4.flat(Infinity); // [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

```