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同樣,沒啥可說的了。看以上例子運行結果就知道了。

相關文章
相關標籤/搜索