原文連結:JavaScript30秒, 從入門到放棄之Array(三)
水平有限,歡迎批評指正
flattenDepth
Flattens an array up to the specified depth.
Use recursion, decrementing
depth
by 1 for each level of depth. UseArray.reduce()
andArray.concat()
to merge elements or arrays. Base case, fordepth
equal to1
stops recursion. Omit the second element,depth
to flatten only to a depth of1
(single flatten).
const flattenDepth = (arr, depth = 1) => depth != 1 ? arr.reduce((a, v) => a.concat(Array.isArray(v) ? flattenDepth(v, depth - 1) : v), []) : arr.reduce((a, v) => a.concat(v), []); 複製程式碼
把一個陣列按指定深度進行攤平。
使用遞迴方法,對於任意級別的深度depth
,每次遞迴depth
減1
。使用Array.reduce()
和Array.concat()
來合併元素們或者陣列們。直到depth
遞減到1
時停止遞迴。省略第二個引數depth
時,按深度depth
為1
計(即單層攤平)。
➜ code cat flattenDepth.js
const flattenDepth = (arr, depth = 1) =>
depth != 1 ?
arr.reduce((a, v) => a.concat(Array.isArray(v) ? flattenDepth(v, depth - 1) : v), []) :
arr.reduce((a, v) => a.concat(v), []);
console.log(flattenDepth([1, [2], 3, 4]));
console.log(flattenDepth([1, [2, [5]], 3, 4]));
➜ code node flattenDepth.js
[ 1, 2, 3, 4 ]
[ 1, 2, [ 5 ], 3, 4 ]
複製程式碼
根據depth
來決定處理流程,若depth
存在且不等於1
則進行遞迴:
arr.reduce((a, v) => a.concat(Array.isArray(v) ? flattenDepth(v, depth - 1) : v), [])
複製程式碼
用了reduce()
去處理迴圈時的每一個值,同時用concat
把所有遞迴結果拼接成新陣列返回。迴圈過程中,對值進行陣列判斷Array.isArray(v)
,是陣列,flattenDepth(v, depth - 1)
深度減1
繼續遞迴直到depth
為1
為止;不是陣列,直接返回該值v
,供concat
拼接。
否則,直接迴圈去拼接該值返回:
arr.reduce((a, v) => a.concat(v), []);
複製程式碼
groupBy
Groups the elements of an array based on the given function.
Use
Array.map()
to map the values of an array to a function or property name. UseArray.reduce()
to create an object, where the keys are produced from the mapped results.
const groupBy = (arr, func) => arr.map(typeof func === 'function' ? func : val => val[func]).reduce((acc, val, i) => { acc[val] = (acc[val] || []).concat(arr[i]); return acc; }, {}); 複製程式碼
按照指定的方法對陣列元素進行分組歸類。
使用Array.map()
對所有陣列元素呼叫指定方法或者呼叫返回該元素的屬性值的方法。使用Array.reduce()
建立一個物件,物件的鍵是map
生成的結果,值是符合該鍵的所有陣列元素組成的陣列。
➜ code cat groupBy.js
const groupBy = (arr, func) =>
arr.map(typeof func === 'function' ? func : val => val[func]).
reduce((acc, val, i) => {
acc[val] = (acc[val] || []).concat(arr[i]);
return acc;
}, {});
console.log(groupBy([6.1, 4.2, 6.3], Math.floor));
console.log(groupBy(['one', 'two', 'three'], 'length'));
➜ code node groupBy.js
{ '4': [ 4.2 ], '6': [ 6.1, 6.3 ] }
{ '3': [ 'one', 'two' ], '5': [ 'three' ] }
複製程式碼
程式碼拆分:
- map
arr.map(typeof func === 'function' ? func : val => val[func])
複製程式碼
對第二個引數func
的型別進行判斷,若是function,則對陣列arr
所有元素呼叫該方法,返回一個新的陣列。如:
const arr = [1, 2, 3, 4];
arr.map(x => x * x); // [1, 4, 9, 16]
複製程式碼
否則,呼叫返回該元素對應func
屬性值方法:
const arr = ['one', 'two', 'three'];
const func = 'length';
arr.map(val => val[func]); // [3, 3, 5]
複製程式碼
- reduce
reduce((acc, val, i) => {
acc[val] = (acc[val] || []).concat(arr[i]);
return acc;
}, {})
複製程式碼
acc
是reduce
過程中累積的結果,val
是reduce
的主體(即前邊map
的結果陣列)每次迴圈時陣列元素的值,i
則是主體陣列迴圈時對應的索引。
第一個迴圈時acc
的初始值是一個空物件{}
,迴圈過程中先判斷是否已經有以val
為鍵的值,如果還沒有,建立一個空陣列把此時對應索引i
的陣列值arr[i]
拼接,作為以val
為鍵的值;否則,直接拼接arr[i]
。即是acc[val] = (acc[val] || []).concat(arr[i])
做的事。每次迴圈都返回acc
物件,直到迴圈結束,生成分類結果。
連起來就是說先對陣列arr
元素進行map
,map
結果作為鍵,所有map
結果相同的陣列元素arr[i]
歸到一個陣列中作為該鍵的值。最終返回一個分好類的物件。
head
Returns the head of a list.
Use
arr[0]
to return the first element of the passed array.
const head = arr => arr[0]; 複製程式碼
返回陣列第一個元素。
使用arr[0]
返回指定陣列arr
的第一個元素。
➜ code cat head.js
const head = arr => arr[0];
console.log(head([1, 2, 3]));
➜ code node head.js
1
複製程式碼
initial
Returns all the elements of an array except the last one.
Use
arr.slice(0,-1)
to return all but the last element of the array.
const initial = arr => arr.slice(0, -1); 複製程式碼
返回除陣列最後一個元素外的所有元素組成的新陣列。
使用arr.slice(0, -1)
返回陣列除最後一個元素外的所有元素。
➜ code cat initial.js
const initial = arr => arr.slice(0, -1);
console.log(initial([1, 2, 3]));
➜ code node initial.js
[ 1, 2 ]
複製程式碼
arr.slice(0, -1)
立竿見影,實在沒啥可說。
initialize2DArray
Initializes a 2D array of given width and height and value.
Use
Array.map()
to generate h rows where each is a new array of size w initialize with value. If the value is not provided, default tonull
.
const initialize2DArray = (w, h, val = null) => Array(h) .fill() .map(() => Array(w).fill(val)); 複製程式碼
初始化一個給定寬(列)、高(行)和值的二維陣列。
使用Array.map()
來生成一個h
行的陣列。每一行含有w
個值為指定值的元素。如果未指定任何值,陣列的預設值是null
。
➜ code cat initialize2DArray.js
const initialize2DArray = (w, h, val = null) => Array(h).fill().map(() => Array(w).fill(val));
console.log(initialize2DArray(2, 2, 0));
➜ code node initialize2DArray.js
[ [ 0, 0 ], [ 0, 0 ] ]
複製程式碼
Array(h).fill()
先建立一個含有h
個元素的陣列並將它們全部預設填充為undefined
。然後在生成的陣列基礎上,每個陣列元素呼叫一個生成w
個元素的陣列且每個位置的值都填充為val
方法。這樣就生成了h
行w
列的二維陣列。
initializeArrayWithRange
Initializes an array containing the numbers in the specified range where
start
andend
are inclusive.Use
Array((end + 1) - start)
to create an array of the desired length,Array.map()
to fill with the desired values in a range. You can omitstart
to use a default value of0
.
const initializeArrayWithRange = (end, start = 0) => Array.from({ length: end + 1 - start }).map((v, i) => i + start); 複製程式碼
初始化一個包含start
和end
的有序數值的陣列。
使用Array((end + 1) - start)
生成所期望的陣列,使用Array.map()
去填充所期望的有序的數值。若省略start
,則start
預設值為0
。
➜ code cat initializeArrayWithRange.js
const initializeArrayWithRange = (end, start = 0) =>
Array.from({
length: end + 1 - start
}).map((v, i) => i + start);
console.log(initializeArrayWithRange(5));
console.log(initializeArrayWithRange(7, 3));
➜ code node initializeArrayWithRange.js
[ 0, 1, 2, 3, 4, 5 ]
[ 3, 4, 5, 6, 7 ]
複製程式碼
{length: end + 1 - start}
生成的陣列長度是end + 1 -start
,而(v, i) => i + start
按i
從0
開始迴圈,直到length - 1
為止。而i + start
則表示元素值從0 + start
開始遞增。
initializeArrayWithValues
Initializes and fills an array with the specified values.
Use
Array(n)
to create an array of the desired length,fill(v)
to fill it with the desired values. You can omitvalue
to use a default value of0
.
const initializeArrayWithValues = (n, value = 0) => Array(n).fill(value); 複製程式碼
初始化一個陣列並全部填充指定值。
Array(n)
生成期望長度的陣列,fill(v)
填充期望的值。若省略第二個引數value
,則value
預設為0
。
➜ code cat initializeArrayWithValues.js
const initializeArrayWithValues = (n, value = 0) => Array(n).fill(value);
console.log(initializeArrayWithValues(5, 2));
➜ code node initializeArrayWithValues.js
[ 2, 2, 2, 2, 2 ]
複製程式碼
Array(n).fill(value)
一步到位,沒啥可說的了。
intersection
Returns a list of elements that exist in both arrays.
Create a
Set
fromb
, then useArray.filter()
ona
to only keep values contained inb
.
const intersection = (a, b) => { const s = new Set(b); return a.filter(x => s.has(x)); }; 複製程式碼
返回兩個陣列的交集。
首先建立一個b
陣列的集合,然後使用Array.filter()
去篩選出a
陣列中存在於b
陣列中的元素。
➜ code cat intersection.js
const intersection = (a, b) => {
const s = new Set(b);
return a.filter(x => s.has(x));
};
console.log(intersection([1, 2, 3], [4, 3, 2]));
➜ code node intersection.js
[ 2, 3 ]
複製程式碼
const s = new Set(b)
先用集合把b
陣列去重,然後a.filter(x => s.has(x))
過濾陣列a
,返回所有存在於s
集合中元素組成的陣列。
last
Returns the last element in an array.
Use
arr.length - 1
to compute the index of the last element of the given array and returning it.
const last = arr => arr[arr.length - 1]; 複製程式碼
返回陣列的最後一個元素。
用arr.length - 1
去計算一個陣列最後一個元素的索引值並返回其對應的陣列元素。
➜ code cat last.js
const last = arr => arr[arr.length - 1];
console.log(last([1, 2, 3]));
➜ code node last.js
3
複製程式碼
mapObject
Maps the values of an array to an object using a function, where the key-value pairs consist of the original value as the key and the mapped value.
Use an anonymous inner function scope to declare an undefined memory space, using closures to store a return value. Use a new
Array
to store the array with a map of the function over its data set and a comma operator to return a second step, without needing to move from one context to another (due to closures and order of operations).
const mapObject = (arr, fn) => (a => ( (a = [arr, arr.map(fn)]), a[0].reduce((acc, val, ind) => ((acc[val] = a[1][ind]), acc), {}) ))(); 複製程式碼
把一個陣列呼叫指定的方法後生成一個物件,物件的鍵是陣列的元素值,物件的值是該元素值呼叫指定方法後生成的結果。
使用內部匿名函式定義一個不汙染全域性變數的名稱空間並用閉包儲存返回值。使用一個新的陣列來儲存一個包含arr
陣列和arr
陣列去map
指定方法後生成的陣列。並在前面陣列的基礎上藉助,
運算子去一步步的生成所需要的物件。避免了上下文環境context
來回轉換(得益於閉包和運算順序)。 (這塊不是太懂)
➜ code cat mapObject.js
const mapObject = (arr, fn) =>
(a => (
(a = [arr, arr.map(fn)]), a[0].reduce((acc, val, ind) => ((acc[val] = a[1][ind]), acc), {})
))();
const squareIt = arr => mapObject(arr, a => a * a);
console.log(squareIt([1, 2, 3]));
➜ code node mapObject.js
{ '1': 1, '2': 4, '3': 9 }
複製程式碼
逗號運算子會返回最後一個運算表示式運算的結果,如:
const i = 0
i + 1, i // i = 1
複製程式碼
即先進行i + 1
運算,為1
,然後返回i
即1
。
以上程式碼含有兩個逗號運算表示式:
((acc[val] = a[1][ind]), acc)
複製程式碼
即先做(acc[val] = a[1][ind])
這個運算,然後返回acc
。
第二個是:
(a = [arr, arr.map(fn)]), a[0].reduce((acc, val, ind) => ((acc[val] = a[1][ind]), acc), {})
複製程式碼
即在a = [arr, arr.map(fn)]
定義了a
的基礎上去運用後面的reduce
方法,最後返回reduce
方法的結果。
可以看出,先定義了一個長度為2的陣列a
,索引0
對應值為陣列arr
,索引1
對應值為陣列arr
呼叫fn
後的map
結果陣列。然後去reduce
生成以arr
元素值為物件鍵(即val
,也即a[0]
陣列遍歷過程中的元素值),以對應該元素值呼叫fn
後的結果值(即a[1][ind]
)為物件值的物件。這個物件就是最終想要的結果。
另外,打一波廣告:一個時間處理庫:now.js,覺得還行的話,點個贊再走唄。。。