原文地址:JavaScript30秒, 從入門到放棄之Array(四)
部落格地址:JavaScript30秒, 從入門到放棄之Array(四)
水平有限,歡迎批評指正
maxN
Returns the
n
maximum elements from the provided array. Ifn
is greater than or equal to the provided array's length, then return the original array(sorted in descending order).Use
Array.sort()
combined with the spread operator (...
) to create a shallow clone of the array and sort it in descending order. UseArray.slice()
to get the specified number of elements. Omit the second argument,n
, to get a one-element array.
const maxN = (arr, n = 1) => [...arr].sort((a, b) => b - a).slice(0, n); 複製程式碼
返回一個陣列的前n個最大值,如果指定的n
大於或等於指定陣列的長度,那麼將返回原陣列(按降序排列後)。
使用Array.sort()
和ES6
的擴充套件運算子…
來生成一個按降序排列的淺度複製陣列。使用Array.slice()
來擷取指定個數的陣列元素。若省略第二個引數n
時,n=1
。
➜ code cat maxN.js
const maxN = (arr, n = 1) => [...arr].sort((a, b) => b - a).slice(0, n);
console.log(maxN([1, 2, 3]));
console.log(maxN([1, 2, 3], 2));
➜ code node maxN.js
[ 3 ]
[ 3, 2 ]
複製程式碼
主要看懂這個sort
就好了:
sort((a, b) => b - a)
複製程式碼
這是降序排的方法,怎麼講?
變形一:
sort(fn(a,b))
複製程式碼
這個fn
呢有兩個引數a
、b
就是陣列排序是按順序相鄰的兩個陣列元素。a
前、b
後。
變形二:
sort((a, b) => {
if (b > a) {
return 1;
} else if (b < a) {
return -1;
}
return 0;
})
複製程式碼
return1
表示把前面的數a
放後面,後面的數b
在放前面;return0
表示不換位置;return-1
表示前面的數a
放前面,後面的數b
放後面。
例子中,當b > a
時把a
換到b
後面,意即把大數放前邊了,即降序排列。反之升序排列。
slice(0, n)
複製程式碼
排完之後slice(0, n)
擷取前n
個元素組成的陣列即為陣列最大的前n
個數。
minN
Returns the
n
minimum elements from the provided array. Ifn
is greater than or equal to the provided array's length, then return the original array(sorted in ascending order).Use
Array.sort()
combined with the spread operator (...
) to create a shallow clone of the array and sort it in ascending order. UseArray.slice()
to get the specified number of elements. Omit the second argument,n
, to get a one-element array.
const minN = (arr, n = 1) => [...arr].sort((a, b) => a - b).slice(0, n); 複製程式碼
返回一個陣列的前n個最小值,如果指定的n
大於或等於指定陣列的長度,那麼將返回原陣列(按升序排列後)。
使用Array.sort()
和ES6
的擴充套件運算子…
來生成一個按升序排列的淺度複製陣列。使用Array.slice()
來擷取指定個數的陣列元素。若省略第二個引數n
時,n=1
。
➜ code cat minN.js
const maxN = (arr, n = 1) => [...arr].sort((a, b) => a - b).slice(0, n);
console.log(maxN([1, 2, 3]));
console.log(maxN([1, 2, 3], 2));
➜ code node minN.js
[ 1 ]
[ 1, 2 ]
複製程式碼
sort((a, b) => a - b)
與maxN
相反,命題得證!
nthElement
Returns the nth element of an array.
Use
Array.slice()
to get an array containing the nth element at the first place. If the index is out of bounds, return[]
. Omit the second argument,n
, to get the first element of the array.
const nthElement = (arr, n = 0) => (n > 0 ? arr.slice(n, n + 1) : arr.slice(n))[0]; 複製程式碼
返回指定陣列的第n
個元素(索引從0算起)。
使用Array.slice()
擷取陣列,使擷取的陣列的第一個元素就是nth
對應的元素。如果索引n
超過陣列範圍,返回空陣列[]
。省略第二個引數n
,按n=0
計。
➜ code cat nthElement.js
const nthElement = (arr, n = 0) => (n > 0 ? arr.slice(n, n + 1) : arr.slice(n))[0];
console.log(nthElement(['a', 'b', 'c'], 1));
console.log(nthElement(['a', 'b', 'b'], -3));
➜ code node nthElement.js
b
a
複製程式碼
就是簡單的用slice
去擷取元素,取擷取後的第一個元素即可。
partition
Groups the elements into two arrays, depending on the provided function's truthiness for each element.
Use
Array.reduce()
to create an array of two arrays. UseArray.push()
to add elements for whichfn
returnstrue
to the first array and elements for whichfn
returnsfalse
to the second one.
const partition = (arr, fn) => arr.reduce( (acc, val, i, arr) => { acc[fn(val, i, arr) ? 0 : 1].push(val); return acc; }, [[], []] ); 複製程式碼
根據提供的方法對一個陣列就行呼叫後,按運算結果的布林值是否為真分類。為真,歸到二維陣列索引為0的陣列中;為假,歸到二維陣列索引為1的陣列中。
使用Array.reduce()
生成一個1x2
的二維陣列。使用Array.push()
把指定fn
運算結果為true
的陣列元素新增到二維陣列的第一個陣列中,運算結果為false
的陣列元素新增到二維陣列的第二個陣列中。
➜ code cat partition.js
const partition = (arr, fn) => arr.reduce((acc, val, i, arr) => {
acc[fn(val, i, arr) ? 0 : 1].push(val);
return acc;
}, [
[],
[]
]);
const users = [{
user: 'Pony',
age: 47,
active: true
}, {
user: 'barney',
age: 36,
active: false
}, {
user: 'fred',
age: 40,
active: true
}];
console.log(partition(users, o => o.active));
➜ code node partition.js
[ [ { user: 'Pony', age: 47, active: true },
{ user: 'fred', age: 40, active: true } ],
[ { user: 'barney', age: 36, active: false } ] ]
複製程式碼
acc
的預設值是一個1x2
的二維空陣列[[], []]
。隨著reduce
的遍歷過程將把滿足對應條件的元素分別push
到對應的陣列中。
acc[fn(val, i, arr) ? 0 : 1].push(val);
複製程式碼
fn(val, i, arr)
如果為true
將會把對應的元素val
新增到acc
的索引為0
的陣列中,否則新增到索引為1
的陣列中。這樣遍歷結束就達到了分組的目的。
例子中,fn
是o => o.active
就是根據物件的active
的屬性是否為true
進行分類,所以我們看到,user
為Pony
和fred
的元素都在二維陣列的索引為0的陣列中,其它在二維陣列的索引為1的陣列中。
pull
Mutates the original array to filter out the values specified.
Use
Array.filter()
andArray.includes()
to pull out the values that are not needed. UseArray.length = 0
to mutate the passed in an array by resetting it's length to zero andArray.push()
to re-populate it with only the pulled values.(For a snippet that does not mutate the original array see without)
const pull = (arr, ...args) => { let argState = Array.isArray(args[0]) ? args[0] : args; let pulled = arr.filter((v, i) => !argState.includes(v)); arr.length = 0; pulled.forEach(v => arr.push(v)); }; 複製程式碼
改變原陣列使其過濾掉指定的那些元素。
使用Array.filter()
和Array.includes()
剔除陣列裡不需要的元素。先用Array.length = 0
把原陣列變成空陣列,然後再通過Array.push()
把過濾後剩餘的元素重新填充進去。
(類似方法不改變原陣列的請看without方法)
➜ code cat pull.js
const pull = (arr, ...args) => {
let argState = Array.isArray(args[0]) ? args[0] : args;
let pulled = arr.filter((v, i) => !argState.includes(v));
arr.length = 0;
pulled.forEach(v => arr.push(v));
};
let myArray = ['a', 'b', 'c', 'a', 'b', 'c'];
pull(myArray, 'a', 'c');
let secondArray = ['a', 'b', 'c', 'a', 'b', 'c'];
pull(secondArray, ['a', 'c'], 'b');
console.log(myArray);
console.log(secondArray);
➜ code node pull.js
args: [ 'a', 'c' ]
args: [ [ 'a', 'b' ], 'c' ]
[ 'b', 'b' ]
[ 'c', 'c' ]
複製程式碼
let argState = Array.isArray(args[0]) ? args[0] : args;
複製程式碼
判斷args
的第一個元素是不是一個陣列,如果是,把該陣列賦值給argState
作為後續排除陣列元素的元陣列;否則args
就是元陣列。
let pulled = arr.filter((v, i) => !argState.includes(v));
複製程式碼
結合filter
和includes
把陣列arr
中包含在argState
中的元素排除掉。
arr.length = 0;
pulled.forEach(v => arr.push(v));
複製程式碼
此處,把陣列長度設為0,將陣列置空,然後再遍歷pulled
,把所有pulled
的元素push
到arr
中,最終arr
就只含有排除掉指定元素後的其他元素。
pullAtIndex
Mutates the original array to filter out the values at the specified indexes.
Use
Array.filter()
andArray.includes()
to pull out the values that are not needed. UseArray.length = 0
to mutate the passed in an array by resetting it's length to zero andArray.push()
to re-populate it with only the pulled values. UseArray.push()
to keep track of pulled values
const pullAtIndex = (arr, pullArr) => { let removed = []; let pulled = arr .map((v, i) => (pullArr.includes(i) ? removed.push(v) : v)) .filter((v, i) => !pullArr.includes(i)); arr.length = 0; pulled.forEach(v => arr.push(v)); return removed; }; 複製程式碼
改變原陣列使其過濾掉指定的那些索引值對應的元素。
使用Array.filter()
和Array.includes()
剔除陣列裡不需要的元素。先用Array.length = 0
把原陣列變成空陣列,然後再通過Array.push()
把過濾後剩餘的元素重新填充進去。同時使用Array.push()
跟蹤記錄剔除掉的所有元素。
➜ code cat pullAtIndex.js
const pullAtIndex = (arr, pullArr) => {
let removed = [];
let pulled = arr.map((v, i) => (pullArr.includes(i) ? removed.push(v) : v))
.filter((v, i) => !pullArr.includes(i));
arr.length = 0;
pulled.forEach((v) => arr.push(v));
return removed;
};
let myArray = ['a', 'b', 'c', 'd'];
let pulled = pullAtIndex(myArray, [1, 3]);
console.log('myArray: ', myArray);
console.log('pulled: ', pulled);
➜ code node pullAtIndex.js
myArray: [ 'a', 'c' ]
pulled: [ 'b', 'd' ]
複製程式碼
let pulled = arr
.map((v, i) => (pullArr.includes(i) ? removed.push(v) : v))
.filter((v, i) => !pullArr.includes(i));
複製程式碼
arr
先map
是為了把要排除掉的元素push
到removed
變數中。pullArr.includes(i) ? removed.push(v) : v
這個三元運算子就是判斷索引是否在要排除掉的指定索引陣列pullArr
中。如果在,新增到removed
中,否則直接返回該元素。
接下來filter
把arr
中匹配pullArr
的索引對應元素剔除掉。
arr.length = 0;
pulled.forEach((v) => arr.push(v));
return removed;
複製程式碼
最後把arr
置空後再填入滿足條件的元素,然後返回剔除掉的元素組成的陣列。
pullAtValue
Mutates the original array to filter out the values specified. Returns the removed elements.
Use
Array.filter()
andArray.includes()
to pull out the values that are not needed. UseArray.length = 0
to mutate the passed in an array by resetting it's length to zero andArray.push()
to re-populate it with only the pulled values. UseArray.push()
to keep track of pulled values
const pullAtValue = (arr, pullArr) => { let removed = [], pushToRemove = arr.forEach((v, i) => (pullArr.includes(v) ? removed.push(v) : v)), mutateTo = arr.filter((v, i) => !pullArr.includes(v)); arr.length = 0; mutateTo.forEach(v => arr.push(v)); return removed; }; 複製程式碼
改變原陣列使其過濾掉指定的那些值所匹配的元素們,返回剔除掉所有元素組成的陣列。
使用Array.filter()
和Array.includes()
剔除陣列裡不需要的元素。先用Array.length = 0
把原陣列變成空陣列,然後再通過Array.push()
把過濾後剩餘的元素重新填充進去。同時使用Array.push()
跟蹤記錄剔除掉的所有元素。
➜ code cat pullAtValue.js
const pullAtValue = (arr, pullArr) => {
let removed = [],
pushToRemove = arr.forEach((v, i) => (pullArr.includes(v) ? removed.push(v) : v)),
mutateTo = arr.filter((v, i) => !pullArr.includes(v));
arr.length = 0;
mutateTo.forEach((v) => arr.push(v));
return removed;
};
let myArray = ['a', 'b', 'c', 'd'];
let pulled = pullAtValue(myArray, ['b', 'd']);
console.log('myArray: ', myArray);
console.log('pulled: ', pulled);
➜ code node pullAtValue.js
myArray: [ 'a', 'c' ]
pulled: [ 'b', 'd' ]
複製程式碼
邏輯上和pullAtIndex
差不多,差別就在一個是過濾索引
,另一個是過濾值
。
為此實現上就有了以下不同:
// pullAtIndex
arr.map((v, i) => (pullArr.includes(i) ? removed.push(v) : v))
// pullAtValue
arr.forEach((v, i) => (pullArr.includes(v) ? removed.push(v) : v))
複製程式碼
一個用了arr.map
,一個用了arr.forEach
。
為什麼呢?
arr.map
後arr
的元素是會改變的,但是對於要剔除掉索引來說要刪除掉索引對應的值是否有變化是無關緊要的。而對於匹配值來說就不靈了,因為本來要剔除掉的值在map
的過程中改變了,到filter
的時候就匹配不出來了,就無法剔除了。
所以改成了arr.forEach
,它是不改變陣列元素的,沒有副作用,不干擾後續filter
。另外forEach
的結果是undefined
。
reducedFilter
Filter an array of objects based on a condition while also filtering out unspecified keys.
Use
Array.filter()
to filter the array based on the predicatefn
so that it returns the objects for which the condition returned a truthy value. On the filtered array, useArray.map()
to return the new object usingArray.reduce()
to filter out the keys which were not supplied as thekeys
argument.
const reducedFilter = (data, keys, fn) => data.filter(fn).map(el => keys.reduce((acc, key) => { acc[key] = el[key]; return acc; }, {}) ); 複製程式碼
根據一個條件對一個陣列進行過濾,同時過濾掉不需要的鍵。
使用Array.filter()
去過濾出指定方法fn
對陣列元素物件呼叫結果為真值的元素,對過濾後的陣列使用Array.map()
返回一個新的物件,物件包含的鍵值對是由Array.reduce()
根據指定keys
過濾掉不需要的鍵而組成的。
➜ code cat reducedFilter.js
const reducedFilter = (data, keys, fn) =>
data.filter(fn).map(el =>
keys.reduce((acc, key) => {
acc[key] = el[key];
return acc;
}, {})
);
const data = [{
id: 1,
name: 'john',
age: 24
}, {
id: 2,
name: 'mike',
age: 50
}];
console.log(reducedFilter(data, ['id', 'name'], item => item.age > 24));
➜ code node reducedFilter.js
[ { id: 2, name: 'mike' } ]
複製程式碼
data.filter(fn)
複製程式碼
陣列data
根據方法fn
過濾掉了不滿足條件的陣列元素。
keys.reduce((acc, key) => {
acc[key] = el[key];
return acc;
}, {})
複製程式碼
keys
是最終要保留的鍵的陣列,reduce
的acc
初始值是空物件{}
,遍歷過程中,把所有的el
物件中鍵包含於keys
陣列所有鍵值對累加到acc
物件中。
map(el => fn1)
複製程式碼
最後聯合map
方法可以看出,最終返回的是一個陣列,陣列內包含fn1
方法也就是keys.reduce
方法返回的acc
的物件。
remove
Removes elements from an array for which the given function returns
false
.Use
Array.filter()
to find array elements that return truthy values andArray.reduce()
to remove elements usingArray.splice()
. Thefunc
is invoked with three arguments (value, index, array
).
const remove = (arr, func) => Array.isArray(arr) ? arr.filter(func).reduce((acc, val) => { arr.splice(arr.indexOf(val), 1); return acc.concat(val); }, []) : []; 複製程式碼
刪除陣列中以指定方法呼叫結果為false
的所有元素。
使用Array.filter()
來找出陣列中所有執行指定方法結果為真的元素,使用Array.reduce()
配合Array.splice()
刪除掉不需要的元素。func
函式呼叫有三個引數(value, index, array)
。
➜ code cat remove.js
const remove = (arr, func) =>
Array.isArray(arr) ?
arr.filter(func).reduce((acc, val) => {
arr.splice(arr.indexOf(val), 1);
return acc.concat(val);
}, []) : [];
const arr = [1,2,3,4];
console.log(remove(arr, n => n % 2 == 0));
console.log(arr);
➜ code node remove.js
[ 2, 4 ]
[ 1, 3 ]
複製程式碼
Array.isArray(arr) ? filterfun : [];
複製程式碼
先判斷給定引數arr
是否是一個陣列,是,執行filter
函式;否,直接返回結果空陣列[]
。
arr.filter(func).reduce((acc, val) => {
arr.splice(arr.indexOf(val), 1);
return acc.concat(val);
}, [])
複製程式碼
arr.filter(func)
首先過濾出func
執行結果為真所有陣列元素。reduce
方法將filter
剩餘的所有陣列元素以concat
的方式返回結果陣列。而在原陣列arr
中,則用splice
將func
執行結果為真的所有元素剔除。
其實就最終的返回結果來說,arr.filter(func)
已經可以返回正確的結果,之所以看起來多此一舉的使用了reduce
的原因在於必須把不需要的元素從原陣列arr
中剔除。
以下是我在沒看程式碼之前根據例子執行結果先寫的程式碼:
➜ code cat remove1.js
const remove = (arr, fn) => {
let removed = [];
arr.forEach(v => (fn(v) ? removed.push(v) : v));
const left = arr.filter(v => !fn(v));
arr.length = 0;
left.forEach(v => arr.push(v));
return removed;
};
const arr = [1,2,3,4];
console.log(remove(arr, n => n % 2 == 0));
console.log(arr);
➜ code node remove1.js
[ 2, 4 ]
[ 1, 3 ]
複製程式碼
我認為程式碼本身應該沒什麼問題,但可能沒那麼優雅,另外就是沒有做Array.isArray
的前置條件判斷。
sample
Returns a random element from an array.
Use
Math.random()
to generate a random number, multiply it bylength
and round it of to the nearest whole number usingMath.floor()
. This method also works with strings.
const sample = arr => arr[Math.floor(Math.random() * arr.length)]; 複製程式碼
返回陣列中隨機的一個元素。
使用Math.random()
生成一個隨機數,乘以陣列的長度,然後再配以Math.floor()
獲取整數索引,進而返回該索引對應的陣列元素。這個方法也同樣適用於字串。
➜ code cat sample.js
const sample = (arr) => arr[Math.floor(Math.random() * arr.length)]
console.log(sample([3, 7, 9, 11]));
➜ code node sample.js
7
複製程式碼