iT邦幫忙

第 11 屆 iT 邦幫忙鐵人賽

DAY 10
6

今天要介紹第三個資料結構 Map,此 Map 跟 Array.prototype.map 可是完全不一樣的東西! 千萬不要搞錯了。
https://ithelp.ithome.com.tw/upload/images/20190919/20106426AJgBlvLJre.jpg

不同程式語言都有屬於他們的 data collection,例如 Python 有 lists、tuples、dictionaries; Java 有 lists、sets、maps、queues; Ruby 有 hashes 跟 arrays。但 javaScript... 恩,只有 Array。導致 javaScript 工程師在學資料結構時比其他語言工程師難上許多 (平常根本不會碰到阿 !!! )。

好在 ES6 增加了 Set 跟 Map 語法。讓 javaScript 終於可以用更簡潔的語法一窺究竟別種資料結構。

在前一章我們學到元素不會重覆的 Set,今天我們繼續討論另外一種不重複值的資料結構 Map。Set 關心的是元素 { value1, value2 },Map 關心的是 { 鍵(key): 值(value)} 之間的關係。

在查資料時除了 Map 還看到一堆別的專有名詞,但基本上 Map、 dictionaries、associative arrays、hashtable 都是在形容一樣資料結構 (就像北部叫橡皮擦南部叫擦子但明明是一樣東西的概念)。


來建立 Map 吧

會發現 key 值什麼型態都可以

// ES6 Map
let myMap= new Map();

var keyString = 'I am string',
    keyObj = {},
    keyFunc = function() {},
    keyNumber = 1

// 增加
myMap.set(keyString , 'string value');
myMap.set(keyObj, {obj: 1});
myMap.set(keyFunc , function(){console.log('I am function')});
myMap.set(keyNumber , 100);

// 有幾個
myMap.size; // 4

// 取值
myMap.get(keyObj); // {obj: 1}

// 看是否存在
myMap.has(keyString ); //  true

// 刪掉
myMap.delete(keyNumber); 
myMap.size; // 3

// 轉陣列
[...myMap.values()] // ["string value", {obj: 1}, ƒ]

當然你要一開始就把值存進去也可以。
更多 Map 方法可以看 MDN

// have value when define
let myMap = new Map([[keyString ,'string value'], [keyObj, {obj: 1}]]);

來聊聊 Map

https://ithelp.ithome.com.tw/upload/images/20190911/20106426d8zmONmzIv.jpg
之前再介紹 Array 的時候提過,Array 是儲存資料的箱子,而每一個箱子外面都會貼一個 index 標籤。假如你記得西瓜是放在 "0",那就直接去標籤為 0 的箱子拿西瓜 Big O(1)。但如果忘記標籤是甚麼就要每一個箱子都打開檢查 Big O(n)
https://ithelp.ithome.com.tw/upload/images/20190911/201064264HaKUSVqog.jpg
而 map 像是貼有名字的標籤,一目了然連記都不用記,想拿西瓜,直接打開貼有西瓜標籤的箱子就好。
有人可能會想說那我也可以用 Object 記阿! 是的。但 Map 特別之處就在他的標籤 (key),不像 Object 一定要是 String ,它可以是 Number、Array、Object 或其他任何型別。(下一篇會再詳細比較 Object 跟 Map)

另外雖然 Array 每一個箱子都有貼 index 標籤,但 Array index 基本跟他的 value 沒有任何關係的。
例如我想知道每種水果被吃了幾個

Array

https://ithelp.ithome.com.tw/upload/images/20190911/20106426ysjA57nCV2.jpg

// array 需要兩個陣列來記錄
fruitsArr = ['watermelon', 'grape', 'avocado']  // store friut
ateCount = [0 , 1, 4]  // store how many times eat
// 沒有人吃西瓜、葡萄被吃了一個、酪梨被吃 4 個

有 n 個水果,我們要先找 target 水果在不在 fruitsArr 裡,如果有,就在 ateCount 找到相對應 index 然後 +1, 這樣找下來有兩層 loop 時間複雜度是 Big O(n²)

Map

https://ithelp.ithome.com.tw/upload/images/20190911/20106426FnvGpk3RGJ.jpg

// map
let fruitsMap = new Map([['watermelon',0], ['grape', 1], ['avocado', 4]]);

有 n 個水果,我們要先找 target 水果在不在 fruitsMap 的 Key 裡,有就直接對的 value +1,時間複雜度是 Big O(n),效率比 Array 好很多

如何運用在專案裡

自己才剛學 Map 馬上發現它的好處,案子有一個需求是使用者可以勾選任意項目並修改價錢,按儲存後 post API
https://ithelp.ithome.com.tw/upload/images/20190911/20106426HqnDayM1OL.jpg
https://ithelp.ithome.com.tw/upload/images/20190911/20106426qXy10Smw9Q.jpg
原本的 get product list API

// data
[
	{
	"id" : 0,
	"product":  'watermelon',
	"price": 100
	},
	{
	"id" : 1,
	"product":  'apple',
	"price": 50
	},
	{
	"id" : 2,
	"product":  'banana',
	"price": 99
	},
  ...
	{
	"id" : 50,
	"product":  'avocado',
	"price": 99
	},
]

修改完價錢 change price API 丟的資料要長這樣

// 可以是 multiple 的
[{"id":xx,"price":xx}, {"id":xx,"price":xx}]

我的做法就是當使用者勾選並改價錢就去記錄他的 id 跟 price。當然實際程式碼會判斷更多東西,我只是先簡單列出來

// 存修改哪個商品並把修改後價錢存起來
let tmpChagePrice = new Map();

tmpChagePrice.set(0, {"price": 200})
tmpChagePrice.set(50, {"price": 99})

// 儲存後 post API
let data = [];
this.tempList.forEach( (v, i) => {
      data.push({
        "id": i,
        "price": v.price
      })
})

是不是很容易呢!當然假如有更好作法歡迎跟我說 ~~

如有錯誤或需要改進的地方,拜託跟我說。
我會以最快速度修改,感謝您

上一篇
[LeetCode #217, #804] Set
下一篇
Map vs. Object
系列文
前端工程師用 javaScript 學演算法32

尚未有邦友留言

立即登入留言