原文地址:JavaScript30秒, 从入门到放弃之Array(六)博客地址:JavaScript30秒, 从入门到放弃之Array(六)
水平有限,欢迎批评指正
tail
Returns all elements in an array except for the first one.
Return
Array.slice(1)
if the array'slength
is more than1
, otherwise, return the whole array.const tail = arr => (arr.length > 1 ? arr.slice(1) : arr);
返回除了数组第一个元素以外的所有元素。
如果数组长度大于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.
Use
Array.slice()
to create a slice of the array withn
elements taken from the beginning.const take = (arr, n = 1) => arr.slice(0, n);
返回一个由数组的前n
个元素组成的新数组。
用Array.slice()
创建一个新的数组,数组元素由指定数组的前n
个元素组成。
➜ 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 withn
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 overArray.keys()
until the returned value from the function istrue
. Return the removed elements, usingArray.reverse()
andArray.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; };
从数组尾部开始删除元素,直到对数组元素运用指定方法fn
为true
为止。同时返回被删除的元素。
循环数组,使用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())
循环数组arr
的key
值,即索引,因为是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 overArray.keys()
until the returned value from the function istrue
. Return the removed elements, usingArray.slice()
.const takeWhile = (arr, func) => { for (let i of arr.keys()) if (func(arr[i])) return arr.slice(0, i); return arr; };
从数组索引为0
开始删除元素,直到对数组元素运用指定方法fn
为true
为止。同时返回被删除的元素。
➜ 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 ofa
andb
and convert to an array.const union = (a, b) => Array.from(new Set([...a, ...b]));
返回两个数组的并集(像集合的并集一样,不包含重复元素)。
创建一个以a
和b
数组为元素的集合并把它转化成数组。
➜ 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
扩展运算符…
也能达到效果。
原理太简单,创建a
和b
数组的集合自然把他们两者的重复元素去掉了。
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 allfn
to all values ofa
. Create aSet
froma
and all elements inb
whose value, after applyingfn
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 ofa
and values inb
for which the comparator finds no matches ina
, usingArray.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
方法去把所有对a
和b
的元素调用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. UseArray.reduce()
andArray.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. UseArray.reduce()
andArray.forEach()
to map grouped values to individual arrays. UseArray.map()
and the spread operator (...
) to applyfn
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
一样,没啥可说的了。看以上例子运行结果就知道了。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。