136 lines
4.2 KiB
Markdown
136 lines
4.2 KiB
Markdown
|
# Boutique Suggestions
|
||
|
|
||
|
Welcome to Boutique Suggestions on Exercism's Elixir Track.
|
||
|
If you need help running the tests or submitting your code, check out `HELP.md`.
|
||
|
If you get stuck on the exercise, check out `HINTS.md`, but try and solve it without using those first :)
|
||
|
|
||
|
## Introduction
|
||
|
|
||
|
## List Comprehensions
|
||
|
|
||
|
Comprehensions provide a facility for transforming _Enumerables_ easily and declaratively.
|
||
|
|
||
|
To declare a very simple comprehension, we can use the `for` keyword followed by a _generator_ and a _do-block_ which creates the new values from the enumerated values.
|
||
|
|
||
|
```elixir
|
||
|
for n <- [0, 1, 2, 3], do: n + 1
|
||
|
# => [1, 2, 3, 4]
|
||
|
```
|
||
|
|
||
|
Comprehensions can also have _filters_. Values that do not pass the filter are removed from the final list:
|
||
|
|
||
|
```elixir
|
||
|
for n <- [0, 1, 2, 3], n > 1, do: n + 1
|
||
|
# => [3, 4]
|
||
|
```
|
||
|
|
||
|
We can declare more complicated comprehensions over several lines:
|
||
|
|
||
|
```elixir
|
||
|
for {atom, number} <- [a: 1, b: 2, c: 3, d: 4],
|
||
|
rem(number, 2) == 0 do
|
||
|
atom
|
||
|
end
|
||
|
# => [:b, :d]
|
||
|
```
|
||
|
|
||
|
A _cartesian product_ can be created using multiple generators. That means that each value generated by the first generator will be paired once with each value generated by the second generator:
|
||
|
|
||
|
```elixir
|
||
|
for x <- [0, 1],
|
||
|
y <- [0, 1] do
|
||
|
{x, y}
|
||
|
end
|
||
|
# => [{0, 0}, {0, 1}, {1, 0}, {1, 1}]
|
||
|
```
|
||
|
|
||
|
## Instructions
|
||
|
|
||
|
Your work at the online fashion boutique store continues. You come up with the idea for a website feature where an outfit is suggested to the user. While you want to give lots of suggestions, you don't want to give bad suggestions, so you decide to use a list comprehension since you can easily _generate_ outfit combinations, then _filter_ them by some criteria.
|
||
|
|
||
|
Clothing items are stored as a map:
|
||
|
|
||
|
```elixir
|
||
|
%{
|
||
|
item_name: "Descriptive Name",
|
||
|
price: 99.00,
|
||
|
base_color: "red"
|
||
|
}
|
||
|
```
|
||
|
|
||
|
## 1. Suggest a combination
|
||
|
|
||
|
Implement `get_combinations/3` to take a list of tops, a list of bottoms, and keyword list of options. For now, set options to default to an empty keyword list. The function should return the cartesian product of the lists.
|
||
|
|
||
|
```elixir
|
||
|
tops = [
|
||
|
%{item_name: "Dress shirt"},
|
||
|
%{item_name: "Casual shirt"}
|
||
|
]
|
||
|
bottoms = [
|
||
|
%{item_name: "Jeans"},
|
||
|
%{item_name: "Dress trousers"}
|
||
|
]
|
||
|
BoutiqueSuggestions.get_combinations(tops, bottoms)
|
||
|
# => [
|
||
|
# {%{item_name: "Dress shirt"}, %{item_name: "Jeans"}},
|
||
|
# {%{item_name: "Dress shirt"}, %{item_name: "Dress trousers"}},
|
||
|
# {%{item_name: "Casual shirt"}, %{item_name: "Jeans"}},
|
||
|
# {%{item_name: "Casual shirt"}, %{item_name: "Dress trousers"}}
|
||
|
# ]
|
||
|
```
|
||
|
|
||
|
## 2. Filter out clashing outfits
|
||
|
|
||
|
Each piece of clothing has a `:base_color` field, use this field to filter out all combinations where the top and the bottom have the same base color.
|
||
|
|
||
|
```elixir
|
||
|
tops = [
|
||
|
%{item_name: "Dress shirt", base_color: "blue"},
|
||
|
%{item_name: "Casual shirt", base_color: "black"}
|
||
|
]
|
||
|
bottoms = [
|
||
|
%{item_name: "Jeans", base_color: "blue"},
|
||
|
%{item_name: "Dress trousers", base_color: "black"}
|
||
|
]
|
||
|
BoutiqueSuggestions.get_combinations(tops, bottoms)
|
||
|
# => [
|
||
|
# {%{item_name: "Dress shirt", base_color: "blue"},
|
||
|
# %{item_name: "Dress trousers", base_color: "black"}},
|
||
|
# {%{item_name: "Casual shirt", base_color: "black"},
|
||
|
# %{item_name: "Jeans", base_color: "blue"}}
|
||
|
# ]
|
||
|
```
|
||
|
|
||
|
## 3. Filter by combination price
|
||
|
|
||
|
Each piece of clothing has a `:price` field associated with it. While you want to give lots of suggestions, you want to be able to provide users an opportunity to select a price within their budget. From the keyword list of options, use `:maximum_price` to filter out combinations where the price of the top and bottom exceed the maximum price.
|
||
|
|
||
|
If no maximum_price is specified, the default should be `100.00`
|
||
|
|
||
|
```elixir
|
||
|
tops = [
|
||
|
%{item_name: "Dress shirt", base_color: "blue", price: 35},
|
||
|
%{item_name: "Casual shirt", base_color: "black", price: 20}
|
||
|
]
|
||
|
bottoms = [
|
||
|
%{item_name: "Jeans", base_color: "blue", price: 30},
|
||
|
%{item_name: "Dress trousers", base_color: "black", price: 75}
|
||
|
]
|
||
|
BoutiqueSuggestions.get_combinations(tops, bottoms, maximum_price: 50)
|
||
|
# => [
|
||
|
# {%{item_name: "Casual shirt", base_color: "black", price: 20},
|
||
|
# %{item_name: "Jeans", base_color: "blue", price: 30}}
|
||
|
# ]
|
||
|
```
|
||
|
|
||
|
## Source
|
||
|
|
||
|
### Created by
|
||
|
|
||
|
- @neenjaw
|
||
|
|
||
|
### Contributed to by
|
||
|
|
||
|
- @angelikatyborska
|
||
|
- @kevpo
|