學習軌道
/
Elixir
Elixir
/
練習
/
精品店庫存
精品店庫存

精品店庫存

學習練習

簡介

Enum

Enum是一個非常實用的模組,提供了一組處理可列舉資料的演算法。它提供排序、篩選、分組、計數、搜尋、尋找最小/最大值等功能。

一般而言,_可列舉_是指任何可以被疊代的資料,也就是集合。在 Elixir 中,可列舉是指任何實作了Enumerable協定的資料型態。其中最常見的是陣列和映射。

許多Enum函式會接受函式作為引數。

Enum.all?([1, 2, 3, 4, 5], fn x -> x > 3 end)
# => false

最常見的Enum函式是map和reduce。

map/2

Enum.map/2讓你可以把可列舉中的每個元素替換成另一個元素。Enum.map/2的第二個引數是一個函式,它接受原始元素並回傳取代它的新元素。

reduce/3

Enum.reduce/3讓你可以把整個可列舉_縮減_成單一值。為了做到這件事,會使用一個稱為_累加器_的特殊變數。累加器會在每次疊代之間攜帶縮減過程的中間狀態。

Enum.reduce/3的第二個引數是累加器的初始值。第三個引數是一個函式,它接受一個元素和一個累加器,並回傳累加器的新值。

處理映射

當把映射和Enum函式一起使用時,映射會自動轉換成由 2 個{key, value}元組組成的陣列。

若要把它轉換回映射,請使用Enum.into/2。Enum.into/2是一個把可列舉轉換成可收集的函式,可收集是指任何實作了Collectable協定的資料結構。可以把它想成Enum.reduce/3的相反。

Enum也有Enum.into/3。Enum.into/3是Enum.into/2的變化版本,它接受一個轉換函式,在把可列舉轉換成可收集的過程中套用。

對映射套用映射

除了使用Enum.into/3或Enum.map/2加上Enum.into/2來對映射套用轉換(映射)之外,我們也可以使用專門的Map.new/2函式。它的運作方式和Enum.into/3完全一樣,接受一個可列舉和一個轉換函式,但它一定回傳一個新的映射,而不是讓我們選擇可收集。

說明

你正在經營一家線上時尚精品店。一年一度的大拍賣即將到來,你得清點庫存,確保一切就緒。

庫存裡的單一商品以映射表示,而整份庫存就是這些映射的陣列。

%{
  name: "White Shirt",
  price: 40,
  quantity_by_size: %{s: 3, m: 7, l: 8, xl: 4}
}

1. 依價格排序商品

實作sort_by_price/1函式。它應該接收庫存,並回傳依商品價格由小到大排序後的結果。

BoutiqueInventory.sort_by_price([
  %{price: 65, name: "Maxi Brown Dress", quantity_by_size: %{}},
  %{price: 50, name: "Red Short Skirt", quantity_by_size: %{}},
  %{price: 50, name: "Black Short Skirt", quantity_by_size: %{}},
  %{price: 20, name: "Bamboo Socks Cats", quantity_by_size: %{}}
])

# => [
#      %{price: 20, name: "Bamboo Socks Cats", quantity_by_size: %{}},
#      %{price: 50, name: "Red Short Skirt", quantity_by_size: %{}},
#      %{price: 50, name: "Black Short Skirt", quantity_by_size: %{}},
#      %{price: 65, name: "Maxi Brown Dress", price: 65, quantity_by_size: %{}}
#    ]

2. 找出缺少價格的商品

把庫存依價格排序之後,你發現自己在清點時犯了一個錯誤,忘了填寫幾件商品的價格。

實作with_missing_price/1函式。它應該接收庫存,並回傳沒有價格的商品陣列。

BoutiqueInventory.with_missing_price([
  %{price: 40, name: "Black T-shirt", quantity_by_size: %{}},
  %{price: nil, name: "Denim Pants", quantity_by_size: %{}},
  %{price: nil, name: "Denim Skirt", quantity_by_size: %{}},
  %{price: 40, name: "Orange T-shirt", quantity_by_size: %{}}
])

# => [
#      %{price: nil, name: "Denim Pants", quantity_by_size: %{}},
#      %{price: nil, name: "Denim Skirt", quantity_by_size: %{}}
#    ]

3. 更新商品名稱

你注意到有些商品名稱裡有你不想再使用的字詞。現在你要把所有含有那個字詞的商品名稱都更新掉。

實作update_names/3函式。它應該接收庫存、你想移除的舊字詞,以及你想改用的新字詞,並回傳名稱已更新的商品陣列。

BoutiqueInventory.update_names(
  [
    %{price: 40, name: "Black T-shirt", quantity_by_size: %{}},
    %{price: 70, name: "Denim Pants", quantity_by_size: %{}},
    %{price: 65, name: "Denim Skirt", quantity_by_size: %{}},
    %{price: 40, name: "Orange T-shirt", quantity_by_size: %{}}
  ],
  "T-shirt",
  "Tee"
)

# => [
#      %{price: 40, name: "Black Tee", quantity_by_size: %{}},
#      %{price: 70, name: "Denim Pants", quantity_by_size: %{}},
#      %{price: 65, name: "Denim Skirt", quantity_by_size: %{}},
#      %{price: 40, name: "Orange Tee", quantity_by_size: %{}}
#    ]

4. 增加商品的數量

有幾件商品賣得特別好,所以你又訂了更多,而且每個尺寸都訂。

實作increase_quantity/2函式。它應該接收單一商品和一個數字n,並回傳該商品,其中每個尺寸的數量都增加n。

BoutiqueInventory.increase_quantity(
  %{
    name: "Polka Dot Skirt",
    price: 68,
    quantity_by_size: %{s: 3, m: 5, l: 3, xl: 4}
  },
  6
)

# => %{
#      name: "Polka Dot Skirt",
#      price: 68,
#      quantity_by_size: %{l: 9, m: 11, s: 9, xl: 10}
#    }

5. 計算商品的總數量

為了知道倉庫需要多大的空間,你得知道每件商品總共有多少存貨。

實作total_quantity/1函式。它應該接收單一商品,並回傳你不分尺寸的總件數。

BoutiqueInventory.total_quantity(%{
  name: "Red Shirt",
  price: 62,
  quantity_by_size: %{s: 3, m: 6, l: 5, xl: 2}
})

# => 16
透過 GitHub 編輯 連結會在新視窗或分頁中開啟
Elixir Exercism

準備好開始 精品店庫存 了嗎?

註冊 Exercism,透過 58 個概念168 個練習 和真人引導來學習並精通 Elixir,全部免費。