# Day 4:Array Cardio Day 1
[竹白記事本](https://chupainotebook.blogspot.com/),Javascript 30,紀錄。
###### tags: `Javascript 30`
## 實現效果
陣列資料處理練習。
- [原始碼](https://github.com/chupai/JS30/tree/master/source_code/Day04)
## 重點
沒啥重點,就資料處理。
## 基礎語法
### JavaScrit
- `Array.prototype`
- `filter()`
- `map()`
- `sort()`
- `reduce()`
>[陣列與批次操作](https://hackmd.io/7_PfOokERX-kgUUL4UQOZQ)
## 說明
### 1. 資料
共有三筆資料:
- `inventors`
- `people`
- `data`
```javascript
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 }
];
const people = ['Beck, Glenn', 'Becker, Carl', 'Beckett, Samuel', 'Beddoes, Mick', 'Beecher, Henry', 'Beethoven, Ludwig', 'Begin, Menachem', 'Belloc, Hilaire', 'Bellow, Saul', 'Benchley, Robert', 'Benenson, Peter', 'Ben-Gurion, David', 'Benjamin, Walter', 'Benn, Tony', 'Bennington, Chester', 'Benson, Leana', 'Bent, Silas', 'Bentsen, Lloyd', 'Berger, Ric', 'Bergman, Ingmar', 'Berio, Luciano', 'Berle, Milton', 'Berlin, Irving', 'Berne, Eric', 'Bernhard, Sandra', 'Berra, Yogi', 'Berry, Halle', 'Berry, Wendell', 'Bethea, Erin', 'Bevan, Aneurin', 'Bevel, Ken', 'Biden, Joseph', 'Bierce, Ambrose', 'Biko, Steve', 'Billings, Josh', 'Biondo, Frank', 'Birrell, Augustine', 'Black, Elk', 'Blair, Robert', 'Blair, Tony', 'Blake, William'];
const data = ['car', 'car', 'truck', 'truck', 'bike', 'walk', 'car', 'van', 'bike', 'walk', 'car', 'van', 'car', 'truck' ];
```
### 2. 小技巧
如果要查看資料, [`console.table()`](https://developer.mozilla.org/zh-CN/docs/Web/API/Console/table) 會比 `console.log()` 來得直觀,它可將資料以表格的形式顯示,
## 實作
### 問題 1
Filter the list of inventors for those who were born in the 1500's.
從 `inventors` 篩選 15世紀(1500-1599)出生的。
```javascript
let ans1 =inventors.filter(function(inventor) {
return inventor.year >= 1500 && inventor.year < 1600;
});
console.table(ans1);
```
`filter()` 會回傳一個新陣列,其條件是 `return` 後方為 `true` 的物件,很適合用在搜尋符合條件的資料。
使用 [ES6 箭頭函式](https://developer.mozilla.org/zh-TW/docs/Web/JavaScript/Reference/Functions/Arrow_functions),更簡化
```javascript
let ans1 = inventors.filter(
inventor => inventor.year >= 1500 && inventor.year < 1600
);
```
### 問題 2
Give us an array of the inventors' first and last names.
將 `inventors` 的 `first` 與 `last` 組合成一個陣列。
```javascript
let ans2 = inventors.map(inventor => `${inventor.first} ${inventor.last}`);
```
`map()` 需要回傳一個值,他會透過函式內所回傳的值組合成一個新陣列。
- 如果不回傳則是 `undefined`
- 回傳數量等於原始陣列的長度
`map()` 與 `forEach()` 差別:
`forEach()` 不會額外回傳值,只單純執行每個陣列內的物件或值。
如果要使用 `forEach()` 達成一樣功能,就要新增一個空陣列,並使用 `push` 將內容丟進空陣列。
```javascript
let ans2 = [];
inventors.forEach(inventor =>
ans2.push(`${inventor.first} ${inventor.last}`)
);
```
### 問題 3
Sort the inventors by birthdate, oldest to youngest.
將 `inventor` 依據生日由大至小排序。
```javascript
let ans3 = inventors.sort((a, b) => a.year - b.year);
```
`sort()` 方法會原地(in place)對一個陣列的所有元素進行排序,並回傳此陣列。
排序不一定是穩定的,各家瀏覽器都不同,可以參考 **[從 Array 的 sort 方法,聊到各瀏覽器的實作,沒想到 Chrome 和FireFox 的排序如此不同](https://medium.com/@realdennis/javascript-%E5%BE%9Earray%E7%9A%84sort%E6%96%B9%E6%B3%95-%E8%81%8A%E5%88%B0%E5%90%84%E5%AE%B6%E7%80%8F%E8%A6%BD%E5%99%A8%E7%9A%84%E5%AF%A6%E4%BD%9C%E7%AE%97%E6%B3%95-c23a335b1b80)** 這篇文章。
### 問題 4
How many years did all the inventors live?
`inventor` 在世期間總和?
```javascript
let total = inventors.reduce((total, inventor) => {
return total + inventor.passed - inventor.year;
}, 0);
```
[`reduce()`](https://developer.mozilla.org/zh-TW/docs/Web/JavaScript/Reference/Global_Objects/Array/Reduce) 方法將一個累加器及陣列中每項元素(由左至右)傳入回呼函式,將陣列化為單一值。
詳細可參考 [JavaScript 中 `reduce()` 方法不完全指南](https://aotu.io/notes/2016/04/14/js-reduce/index.html)。
不用 `reduce()` 的作法:
```javascript
let total = 0;
inventors.forEach(inventor => {
total += inventor.passed - inventor.year;
});
```
### 問題 5
Sort the inventors by years lived.
將 `inventor` 依據年齡由大至小排序所有的。
```javascript
let ans5 = inventors.sort((a, b) => {
return (a.passed - a.year) - (b.passed - b.year);
});
```
### 問題 6
create a list of Boulevards in Paris that contain 'de' anywhere in the name.
到 [`wiki`](https://en.wikipedia.org/wiki/Category:Boulevards_in_Paris) 網頁,列出所有包含 `'de'` 的路名。
```javascript
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'));
```
`querySelectorAll()` 出來的是 `NodeList`,沒有 `map()` 方法,所以要先用 `Array.from()` 轉陣列。
[`include()`](https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Array/includes)方法用來判斷一個陣列是否包含一個指定的值,根據情況,如果包含則返回 `true`,否則返 `false`。
### 問題 7
Sort the people alphabetically by last name.
`people` 的 `lastName` 依據字母順序排序。
```javascript
let ans7 = people.sort((a, b) => {
let [aFirst, aLast] = a.split(', ');
let [bFirst, bLast] = b.split(', ');
return aLast > bLast ? 1 : bLast > aLast ? -1 : 0;
});
// 或是
let ans7 = people.sort((a, b) => {
let aAry = a.split(', ');
let bAry = b.split(', ');
return aAry[1] > bAry[1] ? 1 : bAry[1] > aAry[1] ? -1 : 0;
});
```
使用 `split()` 將名字拆開,再來判斷順序。
[`split()`](https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/String/split) 方法使用指定的分隔符字符串將一個 String 對象分割成字串陣列,以將字符串分隔為子字符串,以確定每個拆分的位置。
### 問題 8
Sum up the instances of each of these.
分別計算 `data` 內每個種類的數量。
首先將累計器的預設值設為空物件 `{}`。
```javascript
let ans8 = data.reduce((obj, item) => {
}, {});
```
接著將物件建立出來,並加 `1`。
```javascript
let ans8 = data.reduce((obj, item) => {
obj[item] = 0
obj[item]++;
return obj
}, {});
console.log( ans8 );
// Object {
// bike: 0,
// car: 0,
// truck: 0,
// van: 0,
// walk: 0
// }
```
但這樣子遇到重複的資料時,不會累加,只會重新將它重設為 `0` 並加 `1`。
因此需要加上判斷式:
```javascript
if(!obj[item]){
obj[item] = 0;
}
```
當 `obj[item]` 不存在就其建立並將值設為 `0`。
這樣遇到重複的資料時,就不會又重設為 `0`,而會累加次數。
```javascript
let ans8 = data.reduce((obj, item) => {
if(!obj[item]){
obj[item] = 0;
}
obj[item]++;
return obj
}, {});
console.log( ans8 );
// Object {
// bike: 2,
// car: 5,
// truck: 3,
// van: 2,
// walk: 2
// }
```