JavaScript30秒, 从入门到放弃之Array(六)

原文地址: JavaScript30秒, 从入门到放弃之Array(六)

博客地址:JavaScript30秒, 从入门到放弃之Array(六)javascript

水平有限,欢迎批评指正java

tail

Returns all elements in an array except for the first one.node

Return Array.slice(1) if the array's length is more than 1, otherwise, return the whole array.git

const tail = arr => (arr.length > 1 ? arr.slice(1) : arr);

返回除了数组第一个元素之外的全部元素。github

若是数组长度大于1,则用Array.slice(1)返回;不然返回整个数组。数组

➜  code cat tail.js
const tail = arr => (arr.length > 1 ? arr.slice(1) : arr);

console.log(tail([1, 2, 3]));
console.log(tail([1]));
➜  code node tail.js
[ 2, 3 ]
[ 1 ]

take

Returns an array with n elements removed from the beginning.app

Use Array.slice() to create a slice of the array with n elements taken from the beginning.ide

const take = (arr, n = 1) => arr.slice(0, n);

返回一个由数组的前n个元素组成的新数组。oop

Array.slice()建立一个新的数组,数组元素由指定数组的前n个元素组成。rest

➜  code cat take.js
const take = (arr, n = 1) => arr.slice(0, n);

console.log(take([1, 2, 3], 5));
console.log(take([1, 2, 3], 0));
➜  code node take.js
[ 1, 2, 3 ]
[]

n能够指定为0,即一个也不取出。省略则n = 1

takeRight

Returns an array with n elements removed from the end.

Use Array.slice() to create a slice of the array with n elements taken from the end.

const takeRight = (arr, n = 1) => arr.slice(arr.length - n, arr.length);

返回一个由数组的后n个元素组成的新数组。

Array.slice()建立一个新的数组,数组元素由指定数组的后n个元素组成。

➜  code cat takeRight.js
const takeRight = (arr, n = 1) => arr.slice(arr.length - n, arr.length);

console.log(takeRight([1, 2, 3], 2));
console.log(takeRight([1, 2, 3]));

➜  code node takeRight.js
[ 2, 3 ]
[ 3 ]

拿数组后n个元素只需从数组长度减去n的位置开始取到结尾就能够了,slice第二个参数是能够省略的,由于是取到最后一个元素。

takeRightWhile

Removes elements from the end of an array until the passed function returns true. Returns the removed elements.

Loop through the array, using a for...of loop over Array.keys() until the returned value from the function is true. Return the removed elements, using Array.reverse() and Array.slice().

const takeRightWhile = (arr, func) => {
  for (let i of arr.reverse().keys())
    if (func(arr[i])) return arr.reverse().slice(arr.length - i, arr.length);
  return arr;
};

从数组尾部开始删除元素,直到对数组元素运用指定方法fntrue为止。同时返回被删除的元素。

循环数组,使用for…of循环Array.keys()直到对数组元素调用指定方法返回true为止。最后返回删除的全部元素,过程当中结合了Array.reverse()Array.slice()

➜  code cat takeRightWhile.js
const takeRightWhile = (arr, func) => {
  for (let i of arr.reverse().keys())
    if(func(arr[i]))
      return arr.reverse().slice(arr.length - i, arr.length);
    return arr;
};

console.log(takeRightWhile([1, 2, 3, 4], n => n < 3));

➜  code node takeRightWhile.js
[ 3, 4 ]
for (let i of arr.reverse().keys())

循环数组arrkey值,即索引,由于是reverse(),因此是反向循环。如一个数组有五个元素,那么i就是4->3->2->1->0这样的顺序。

if(func(arr[i]))
  return arr.reverse().slice(arr.length - i, arr.length);

对数组元素arr[i]调用func,若真,此时的i就是顺数的第一个该删除的元素的索引,要删除的元素就是今后直到数组结尾为止;即arr.reverse().slice(arr.length - i, arr.length)包含的索引元素。

return arr;

若是前面的整个遍历过程当中func(arr[i])都不为true的话,那就返回原数组,合情合理。

takeWhile

Removes elements in an array until the passed function returns true. Returns the removed elements.

Loop through the array, using a for...of loop over Array.keys() until the returned value from the function is true. Return the removed elements, using Array.slice().

const takeWhile = (arr, func) => {
 for (let i of arr.keys()) if (func(arr[i])) return arr.slice(0, i);
 return arr;
};

从数组索引为0开始删除元素,直到对数组元素运用指定方法fntrue为止。同时返回被删除的元素。

➜  code cat takeWhile.js
const takeWhile = (arr, fn) => {
  for (let i of arr.keys()) if(fn(arr[i])) return arr.slice(0, i);
  return arr;
};

console.log(takeWhile([1, 2, 3, 4], n => n >= 3));

➜  code node takeWhile.js
[ 1, 2 ]

takeRightWhile正好相反,并且还更容易理解。没什么可说的了。

union

Returns every element that exists in any of the two arrays once.

Create a Set with all values of a and b and convert to an array.

const union = (a, b) => Array.from(new Set([...a, ...b]));

返回两个数组的并集(像集合的并集同样,不包含重复元素)。

建立一个以ab数组为元素的集合并把它转化成数组。

➜  code cat union.js
const union = (a, b) => Array.from(new Set([...a, ...b]));

console.log(union([1, 2, 3], [4, 3, 2]));

➜  code node union.js
[ 1, 2, 3, 4 ]

我本身写的以下:

const union = (a, b) => [...new Set([...a, ...b])];

直接用ES6扩展运算符也能达到效果。

原理太简单,建立ab数组的集合天然把他们二者的重复元素去掉了。

unionBy

Returns every element that exists in any of the two arrays once, after applying the provided function to each array element of both.

Create a Set by applying all fn to all values of a. Create a Set from a and all elements in b whose value, after applying fn does not match a value in the previously created set. Return the last set converted to an array.

const unionBy = (a, b, fn) => {
  const s = new Set(a.map(v => fn(v)));
  return Array.from(new Set([...a, ...b.filter(x => !s.has(fn(x)))]));
};

对两个数组的元素分别调用指定方法后,返回以运行结果为断定基准的并集,并集是原始数组元素的并集而不是运行结果的并集。

建立一个a数组调用fn后的集合a1。再建立一个以数组a和对数组b进行过滤全部存在于集合a1中的元素后所剩余元素组成的数组为基准的集合。并把该集合转换成最终的数组。

➜  code cat unionBy.js
const unionBy = (a, b, fn) => {
  const s = new Set(a.map(v => fn(v)));

  return Array.from(new Set([...a, ...b.filter(v => !s.has(fn(v)))]));
};

console.log(unionBy([2.1], [1.2, 2.3], Math.floor));

➜  code node unionBy.js
[ 2.1, 1.2 ]
const s = new Set(a.map(v => fn(v)));

首先得建立其中一个数组的集合s

b.filter(v => !s.has(fn(v)))

这里就是把b数组中全部存在于a调用fn后生成的集合s的元素都删除掉。这样剩下的全部元素和a数组再进行集合运算后再转换成数组。就是咱们所须要的结果。

unionWith

Returns every element that exists in any of the two arrays once, using a provided comparator function.

Create a Set with all values of a and values in b for which the comparator finds no matches in a, using Array.findIndex().

const unionWith = (a, b, comp) =>
  Array.from(new Set([...a, ...b.filter(x => a.findIndex(y => comp(x, y)) === -1)]));

对两个数组的元素分别调用指定比较方法后,返回以运行结果为断定基准的并集,并集是原始数组元素的并集而不是运行结果的并集。

➜  code cat unionWith.js
const unionWith = (a, b, comp) =>
  Array.from(new Set([...a, ...b.filter(x => a.findIndex(y => comp(x, y)) === -1)]));

console.log(unionWith([1, 1.2, 1.5, 3, 0], [1.9, 3, 0, 3.9], (a, b) => Math.round(a) === Math.round(b)));

➜  code node unionWith.js
[ 1, 1.2, 1.5, 3, 0, 3.9 ]

分主客体,这里主体是前一个数组,即a,表示数组a的全部元素都会保留下来。而后循环数组b,用findIndex方法去把全部对ab的元素调用comp比较方法后的结果不存在于a数组中的全部元素筛选出来。最后把筛选出来的全部元素和数组a组成新数组后再进行集合运算并把运算结果转化为数组。那就是unionWith的最终结果。

uniqueElements

Returns all unique values of an array.

Use ES6 Set and the ...rest operator to discard all duplicated values.

const uniqueElements = arr => [...new Set(arr)];

数组去重。

➜  code cat uniqueElements.js
const uniqueElements = arr => [...new Set(arr)];

console.log(uniqueElements([1, 2, 2, 3, 4, 4, 5]));

➜  code node uniqueElements.js
[ 1, 2, 3, 4, 5 ]

结合ES6的扩展运算符和集合便很容易实现。

unzip

Creates an array of arrays, ungrouping the elements in an array produced by zip.

Use Math.max.apply() to get the longest subarray in the array, Array.map() to make each element an array. Use Array.reduce() and Array.forEach() to map grouped values to individual arrays.

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 => [])
  );

对于给定的多个数组,返回一个新的二维数组,数组的第一个元素包含多个数组的第一个元素,数组的第二个元素包含多个数组的第二个元素,以此类推(即把zip方法分好组的数组逆向解组)。

使用Math.max.apply()方法来获取输入数组的子数组元素个数的最大长度,使用Array.map()来把每个元素建立成一个数组。而后使用Array.reduce()Array.forEach()去把组里的元素分别加到各自的数组中。

➜  code cat unzip.js
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 => [])
  );

console.log(unzip([['a', 1, true], ['b', 2, false]]));
console.log(unzip([['a', 1, true], ['b', 2]]));

➜  code node unzip.js
[ [ 'a', 'b' ], [ 1, 2 ], [ true, false ] ]
[ [ 'a', 'b' ], [ 1, 2 ], [ true ] ]
Array.from({
  length: Math.max(...arr.map(x => x.length))
}).map(x => [])

这就是reduce的初始二维数组,用Array.from来生成一个数组,而后再map(x => [])成一个二维数组,那么数组的长度怎么定呢?由于被unzip的原数组里的元素多是长度不一样的数组。那么确定是以长度最长的那个为准,这样才能包含解组后的全部元素。这就是length: Math.max(...arr.map(x => x.length))作的事。

对于reduce里的方法:

(acc, val) => (val.forEach((v, i) => acc[i].push(v)), acc)

acc是累加值,在遍历过程当中会一直变化,val.forEach((v, i) => acc[i].push(v))这是遍历过程当中val数组元素push到累加acc对应索引数组的方法。

举个例子:

原数组arr = [[1, 2, 3], ['a', 'b']],在遍历过程当中初始累加acc = [[], [], []](含有三个元素的数组)。

// 第一次
val = [1, 2, 3]
acc = [[1], [2], [3]]

// 第二次
val = ['a', 'b']
acc = [[1, 'a'], [2, 'b'], [3]] // 这也是最终结果

unzipWith

Creates an array of elements, ungrouping the elements in an array produced by zip and applying the provided function.

Use Math.max.apply() to get the longest subarray in the array, Array.map() to make each element an array. Use Array.reduce() and Array.forEach() to map grouped values to individual arrays. Use Array.map() and the spread operator (...) to apply fn to each individual group of elements.

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));

对于给定的多个数组,返回一个新的二维数组,数组的第一个元素包含多个数组的第一个元素,数组的第二个元素包含多个数组的第二个元素,以此类推(即把zip方法分好组的数组逆向解组),在此基础上对二维数组的每一个元素运行指定方法并返回。

使用Math.max.apply()方法来获取数组的子数组元素个数的最大长度,使用Array.map()来把每个元素建立成一个数组。而后使用Array.reduce()Array.forEach()去把组里的元素分别加到各自的数组中。而后再结合 Array.map()和ES6扩展运算符把前面生成的二维数组的每一个元素分别调用fn方法。

➜  code cat unzipWith.js
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));

console.log(unzipWith([[1, 10, 100], [2, 20, 200]], (...args) => args.reduce((acc, v) => acc + v, 0)));

➜  code node unzipWith.js
[ 3, 30, 300 ]

unzipWith就比unzip多了一个对每一个二维数组元素调用指定fn方法。即map(val => fn(...val))。其它都和unzip同样,没啥可说的了。看以上例子运行结果就知道了。

相关文章
相关标签/搜索