Array method! go go go!


任務拆解

  • Array method
    • fliter()
    • map()
    • sort()
    • reduce()

講師設計幾組可以使用上述method的情境,比官方範例會再有感一點~


filter()

The filter() method creates a new array with all elements that pass the test implemented by the provided function.

by -(MDN web docs)(https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/filter)

一個一個元素被指定的測試函數篩選過濾,根據回傳值是true/false決定是保留還是丟掉,最後返回新陣列。

const words = ['spray', 'limit', 'elite', 'exuberant', 'destruction', 'present'];

const result = words.filter(word => word.length > 6);
//output: Array ["exuberant", "destruction", "present"]

小鴨說code: 宣告words變數,記憶體位址指向一陣列,其中共有6個元素。宣告一變數result用來存結果,使用陣列filter method,測試每一個傳入的element長度是否大於6,若為true則存入result陣列中。


Filter the list of inventors for those who were born in the 1500’s

篩選出1500~1599年出生的人

 const inventors = [
      { first: 'Albert', last: 'Einstein', year: 1879, passed: 1955 },
      { first: 'Isaac', last: 'Newton', year: 1643, passed: 1727 },
      { first: 'Galileo', last: 'Galilei', year: 1564, passed: 1642 },
      { first: 'Marie', last: 'Curie', year: 1867, passed: 1934 },
      { first: 'Johannes', last: 'Kepler', year: 1571, passed: 1630 },
      { first: 'Nicolaus', last: 'Copernicus', year: 1473, passed: 1543 },
      { first: 'Max', last: 'Planck', year: 1858, passed: 1947 },
      { first: 'Katherine', last: 'Blodgett', year: 1898, passed: 1979 },
      { first: 'Ada', last: 'Lovelace', year: 1815, passed: 1852 },
      { first: 'Sarah E.', last: 'Goode', year: 1855, passed: 1905 },
      { first: 'Lise', last: 'Meitner', year: 1878, passed: 1968 },
      { first: 'Hanna', last: 'Hammarström', year: 1829, passed: 1909 }
    ];

let result1 = inventors.filter((item) => {
      return item.year > 1500 && item.year < 1600;
    });
  

 // or 講師解
 
const fifteen = inventors.filter(inventor => (inventor.year >= 1500 && inventor.year < 1600));

// 寫成arrow function 真的很乾淨
// ()=>{}
// 沒有傳入參數還是要有空括號()
// 只是回傳某個值,return可以省
// 只有一個參數,可以省()不寫


result-filter

ps. console.table將資料以表格形式呈現,乾淨無誤!


map()

The **map()** method creates a new array populated with the results of calling a provided function on every element in the calling array.

by -(MDN web docs)(https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map)

一個一個元素透過運算函式再回傳一個新的值,組成新的陣列。陣列長度不變!

一對一重組一個陣列,沒回傳值就給undefined!

const array1 = [1, 4, 9, 16];

// pass a function to map
const map1 = array1.map(x => x * 2);

小鴨說code:宣告一變數array1,位址指向一物件,內容元素依序是1,4,9,16。使用陣列的map method,回傳結果存入map1變數中。每一個傳入的元素x,return x X 2!


Give us an array of the inventors first and last names

取得一陣列,內容為每個發明家first name和 last name的組合!

 let nameArray = inventors.map(item => item.first + ' ' + item.last);
 
 // or 講師解
  const fullNames = inventors.map(inventor => `${inventor.first} ${inventor.last}`);
  
// Template strings!!
// 使用``反引號
// 換行再也不用\n
// ${}可內嵌變數 or 運算式


sort()

The **sort()** method sorts the elements of an array in place and returns the sorted array.

by -MDN web docs

直接in place改變原陣列!!


arr.sort([compareFunction])

可以傳入一comparefunction,省略不寫的話,是依據每元素轉成字串後的unicode進行排序

常見的雷是:數字排序,照數值9會在80前,但因為預設排序會先轉成字串用Unicode排序,變成80在9之前

sort attention

[JavaScript] 從 Array 的 sort 方法,聊到各瀏覽器的實作,沒想到 Chrome 和FireFox 的排序如此不同

有關compare function寫得很詳細!

節錄重點如下:


function compare(a, b) {
  if (在某排序標準下 a 小於 b) {
    return -1;
  }
  if (在某排序標準下 a 大於 b) {
    return 1;
  }
  // a 必須等於 b
  return 0;
}

另一個要小心的就是a,b分別是誰?

in chrome:

chrome compare


in Firefox:

Firefox compare

懶人記法:

// 想要由小往大
arr.sort((a,b)=>a-b);
// 想要由大至小
arr.sort((a,b)=>b-a);

Sort the inventors by birthdate, oldest to youngest

出生年份由小到大排~

 inventors.sort(function (a, b) {
      return a.year - b.year;
    })
    
// or 講師解

 const ordered = inventors.sort((a, b) => a.year > b.year ? 1 : -1);


sort-result


reduce()

The **reduce()** method executes a reducer function (that you provide) on each element of the array, resulting in single output value.

by -MDN web docs

和前次回傳的值再進行運算,最終回傳一個運算結果!


arr.reduce(callback[accumulator, currentValue, currentIndex, array], initialValue)

const array1 = [1, 2, 3, 4];
const reducer = (accumulator, currentValue) => accumulator + currentValue;

// 1 + 2 + 3 + 4
console.log(array1.reduce(reducer));
// expected output: 10

// 5 + 1 + 2 + 3 + 4
console.log(array1.reduce(reducer, 5));
// expected output: 15

accumulator:累加總值, initialvalue:累加前的初始總值, currentvalue:當下元素/變數

小鴨說code: 定義一reducer function,為每次累加當下變數進accumulator中!


How many years did all the inventors live all together?

加總全部人的歲數

const years = inventors
      .map(inventor => inventor.passed - inventor.year)
      .reduce((acc, cur) => acc + cur, 0);
    console.log(years);

// 講師解
 const totalYears = inventors.reduce((total, inventor) => {
      return total + (inventor.passed - inventor.year);
    }, 0);
// 每次計算歲數的結果累計至total中!


綜合情境

Sort the inventors by years lived

將實際歲數排序

 const oldest = inventors
      .sort((a, b) => (b.passed - b.year) - (a.passed - a.year));
    console.table(oldest);
    
// 講師解
    const oldest = inventors.sort(function(a, b) {
      const lastInventor = a.passed - a.year;
      const nextInventor = b.passed - b.year;
      return lastInventor > nextInventor ? -1 : 1;
    });
    console.table(oldest);

create a list of Boulevards in Paris that contain ‘de’ anywhere in the name

取得含有de的名稱,目標資料 https://en.wikipedia.org/wiki/Category:Boulevards_in_Paris

  • 先找出目標來源的classname

find class name


  • 觀察結構

structure


  const category = document.querySelector('.mw-category');
    const links = Array.from(category.querySelectorAll('a'))
    const text = links.map(item => item.textContent)
      .filter(name => name.indexOf('de') > -1);
    console.log(text);
 
 // 講師解
 const category = document.querySelector('.mw-category');
    const links = Array.from(category.querySelectorAll('a'));
    const de = links
                .map(link => link.textContent)
                .filter(streetName => streetName.includes('de'));

sort Exercise Sort the people alphabetically by last name

根據每個人的last name字母做排序

 const alpha = people.sort((pre, next) => {
      const [preLast, nextLast] = [pre.split(', ')[0], next.split(', ')[0]];

      return preLast > nextLast ? 1 : -1;
    })
    
// 講師解
const alpha = people.sort((lastOne, nextOne) => {
      const [aLast, aFirst] = lastOne.split(', ');
      const [bLast, bFirst] = nextOne.split(', ');
      return aLast > bLast ? 1 : -1;
    });
    console.log(alpha);

Reduce Exercise Sum up the instances of each of these

統計運動項目

 const data = ['car', 'car', 'truck', 'truck', 'bike', 'walk', 'car', 'van', 'bike', 'walk', 'car', 'van', 'car',
      'truck'
    ];
 const data = ['car', 'car', 'truck', 'truck', 'bike', 'walk', 'car', 'van', 'bike', 'walk', 'car', 'van', 'car',
      'truck'
    ];
    const sum = data.reduce((obj, cur) => {

      if (!obj[cur]) {
        obj[cur] = 0;
      }

      obj[cur]++;

      return obj;
    }, {})
    console.log(sum);
    
 // 講師解
 const transportation = data.reduce(function (obj, item) {
      if (!obj[item]) {
        obj[item] = 0;
      }
      obj[item]++;
      return obj;
    }, {});

小結&感想

  • Array.prototype
    • filter()
      • 回傳新陣列
    • map()
      • 回傳新陣列
    • sort()
      • 就地改變陣列
    • reduce()
      • 回傳累計的accumulator

寫code習慣很難改過來…..,落落長的寫法要慢慢精簡化!

講師的範例很實在,覺得會更知道要怎麼在實際的專案派上用場。

附上一張emoji版的講解

emoji explained

圖摘自Map, filter, and reduce explained using emoji


參考來源

JavaScript 陣列處理方法 [filter(), find(), forEach(), map(), every(), some(), reduce()]

[JavaScript] 從 Array 的 sort 方法,聊到各瀏覽器的實作,沒想到 Chrome 和FireFox 的排序如此不同