สรุปฟังก์ชันในการจัดการ Elixir Map เบื้องต้น
Tags: elixir
Published: 2020-11-16 06:54:50

ข้อมูลของ Elixir เป็นแบบ immutable ซึ่งกลไกการแก้ไขจัดการข้อมูล แทนที่จะใช้หลักคิดเดียวกันกับภาษาอื่นที่มีตัวแปร หรือ object แล้วใช้การแก้ไขค่าของตัวแปรหรือ object แต่สำหรับ immutable แล้วมองว่าคือการ transforms ไปเป็นค่าใหม่ ซึ่งการ transformation นั้นก็คือใช้ function นั่นเอง

สำหรับ Map แล้วก็จะมี module [Map](https://hexdocs.pm/elixir/Map.html) ที่รวบรวมฟังก์ชันสำหรับจัดการ Map เอาไว้ให้หลายตัว โพสต์นี้จะสรุปที่ใช้บ่อยๆเบื้องต้นเอาไว้หน่อย

## Map.put เพิ่ม key , value ใหม่เข้าไปใน Map
สำหรับภาษาอื่นอ่านจะใช้ท่าแบบนี้ `map[key] = value` ได้เลยแต่สำหรับ Elixir เราจะใช้ function `Map.put` ช่วยแทนเช่น

```elixir
map = %{} # empty map
map = Map.put(map, :name, "Por") # เพิ่ม key :name , value "Por" เข้าไปใน map แล้ว rebinding ที่ตัวแปร map อีกรอ
```

## Map.update ไว้อัพเดทค่าโดยส่ง transformation function เข้าไป
ฟังก์ชันนี้จะรับค่า map ค่า key ที่ต้องการแก้ไข และ ค่า default ถ้าเกิดว่า map ยังไม่มี key นี้มาก่อน สุดท้ายรับ function ที่จะรับค่า value เดิมถ้ามีพร้อมกับ logic ในการแก้ไขค่านั้น ตัวอย่างเช่น

```elixir
map = %{name: "Weerasak"}
map = Map.update(map, :name, "N/A", fn(name) -> "Mr ." <> name end)
```

หรือถ้าต้องการอัพเดทเฉพาะที่มี key เท่านั้นก็ใช้ Map.update! แทนเพราะฟังก์ชันนี้ไม่ต้องมีค่า default แบบนี้

```elixir
map = %{name: "Weerasak"}
map = Map.update!(map, :name, fn(name) -> "Mr ." <> name end) # map = %{name: "Mr. Weerasak"}
```

## Map.delete
ฟังก์ชันนี้จะลบ key ที่ต้องการออกจาก Map เช่น

```elixir
map = %{name: "Weerasak", age: 35}
map = Map.delete(map, :age) # map = %{name: "Weerasak"}
```

## Map.fetch และ Map.fetch!
Map.fetch ให้เพื่อ lookup ค่าจาก Map โดยโดยถ้า key ที่ต้องการไม่เจอจะ return `:error` แต่ถ้าเจอจะ return `{:ok, value}` ส่วน Map.fetch! นั้นถ้าไม่เจอจะเกิด KeyError แต่ถ้าเจอจะได้ค่านั้นออกมาเลย เช่น

```elixir
map = %{name: "Weerasak", age: 35}
{:ok, age} = Map.fetch(map, :age)
age = Map.fetch!(map, :age)
```

## Map.get
Map.get ก็คล้ายๆ Map.fetch ต่างกันตรง Map.get จะสามารถใส่ค่า default ให้ได้ว่าถ้าไม่เจอ key ที่ต้องการจะให้เป็นค่าอะไร ถ้าไม่กำหนดค่า default แล้วไม่เจอ key จะได้ค่า nil กลับมา เช่น

```elixir
map = %{name: "Weerasak", age: 35}
age = Map.get(map, :age) # age == 35
address = Map.get(map, :address) # address == nil
```

## Map.values และ Map.keys
Map.values จะเอาไว้ดึงค่า list ของ values ทั้งหมดใน map ออกมา ส่วน Map.keys ก็เอาไว้ list ค่าของ keys ทั้งหมดออกมาเช่น

```elixir
map = %{name: "Weerasak", age: 35}
values = Map.values(map) # values == ["Weerasak", 35]
keys = Map.keys(map) # keys == [:name, :age]
```

## Map.take, Map.drop และ Map.split
Map.take จะให้เรากรอง map ให้เหลือแต่ keys ที่เราต้องการ ส่วน Map.drop จะเอา keys ที่เราไม่ต้องการออก และ Map.split จะเหมือนกับสั่ง Map.take และ Map.drop พร้อมกันคือจะแยกส่วนที่โดนเลือกกับไม่ได้เลือกออกจากกันเช่น 

```elixir
map = %{a: 1, b: 2, c: 3, d: 4}
take = Map.take(map, [:a, :d]) # take == %{a: 1, d: 4}
drop = Map.drop(map, [:a, :d]) # drop == %{b: 2, c: 3}
split = Map.split(map, [:a, :d]) # split = {%{a: 1, d: 4}, %{b: 2, c: 3}
```

## Map.to_list
Map.to_list จะแปลง Map ให้กลายเป็น list ของ tuple ของ key กับ value แทนเช่น

```elixir
map = %{a: 1, b: 2, c: 3, d: 4}
list = Map.to_list(map) # list == [{:a, 1}, {:b, 2}, {:c, 3}, {:d, 4}]
```

## Map.merge
Map.merge เอาไว้จับ map สองค่ารวมกันโดยที่ถ้า map แรกมี key ซ้ำกับ map ที่สองที่ใช้ค่าของ map ที่สองแทน ถ้าทำซับซ้อนกว่านี้ต้องเพิ่ม function เพื่อเลือกเองว่าจะเอาค่าไหน

```elixir
map = Map.merge(%{a: 1, b: 2}, %{a: 3, d: 4}) # map == %{a: 3, b: 2, d: 4}
```