内包表記を使うと、_Enumerable_を簡単に、宣言的に変換できます。
ごく単純な内包表記は、forキーワードのあとに_ジェネレーター_と_doブロック_を続けて宣言します。_doブロック_が、列挙された値から新しい値を作ります。
for n <- [0, 1, 2, 3], do: n + 1
# => [1, 2, 3, 4]
内包表記には_フィルター_を付けることもできます。フィルターを通過しなかった値は、最終的なリストから取り除かれます。
for n <- [0, 1, 2, 3], n > 1, do: n + 1
# => [3, 4]
より複雑な内包表記は、複数行に分けて書くこともできます。
for {atom, number} <- [a: 1, b: 2, c: 3, d: 4],
rem(number, 2) == 0 do
atom
end
# => [:b, :d]
複数のジェネレーターを使うと、_直積_を作ることができます。つまり、最初のジェネレーターが生成した各値は、2番目のジェネレーターが生成した各値と1回ずつ組み合わされます。
for x <- [0, 1],
y <- [0, 1] do
{x, y}
end
# => [{0, 0}, {0, 1}, {1, 0}, {1, 1}]
オンラインのファッションブティックでの仕事は続きます。ユーザーにコーディネートを提案するウェブサイトの機能を思いつきます。たくさんの提案をしたい一方で、質の悪い提案はしたくありません。そこで、リスト内包表記を使うことにします。コーディネートの組み合わせを簡単に_生成_し、その後、いくつかの条件で_絞り込める_からです。
衣類のアイテムはマップとして保存されています:
%{
item_name: "Descriptive Name",
price: 99.00,
color: "Ochre Red",
base_color: "red"
}
get_combinations/3を実装し、トップスの配列、ボトムスの配列、そしてオプションのキーワードリストを受け取るようにします。とりあえず、オプションのデフォルトは空のキーワードリストにします。関数は、これらの配列の直積を返すようにします。
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"}}
# ]
それぞれの衣類には:base_colorフィールドがあります。このフィールドを使って、トップスとボトムスのベースカラーが同じ組み合わせをすべて除外します。
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"}}
# ]
それぞれの衣類には:priceフィールドが紐づいています。たくさんの提案をしたい一方で、予算内の価格を選べる機会をユーザーに提供したいと考えています。オプションのキーワードリストから:maximum_priceを使い、トップスとボトムスの価格が上限価格を超える組み合わせを除外します。
maximum_priceが指定されていない場合、デフォルトは100.00にします。
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}}
# ]