原文地址: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
一樣,沒啥可說的了。看以上例子執行結果就知道了。