列表解析 (List comprehensions) 是erlang中的语法糖,同样,在elixir中也有对应的语法。
在很多時候,解析可以用来叠代产生更简洁的语句。让我们先来看一个简单的解析,然后拆解它的结构:Enum
Stream
iex> list = [1, 2, 3, 4, 5]
iex> for x <- list, do: x*x
[1, 4, 9, 16, 25]
我們注意到的第一件事是使用 和生成器 (generator)。生成器是什么?生成器是在列表解析中找到的 表達式,它负责产生下一个值。for
x <- [1, 2, 3, 4]
對我們來說幸運的是,解析不僅限於列表,实际上它能在任何举例上使用:
# Keyword Lists
iex> for {_key, val} <- [one: 1, two: 2, three: 3], do: val
[1, 2, 3]
# Maps
iex> for {k, v} <- %{"a" => "A", "b" => "B"}, do: {k, v}
[{"a", "A"}, {"b", "B"}]
# Binaries
iex> for <<c <- "hello">>, do: <<c>>
["h", "e", "l", "l", "o"]
如同 Elixir 中的許多其他東西,生成器依靠模式比對將其輸入集 (input set) 與左側變數進行比較。在無法找到配對的情況下,該值將被忽略:
iex> for {:ok, val} <- [ok: "Hello", error: "Unknown", ok: "World"], do: val
["Hello", "World"]
可以同時使用多個生成器,就像巢狀迴圈一樣 (nested loops):
iex> list = [1, 2, 3, 4]
iex> for n <- list, times <- 1..n do
iex> String.duplicate("*", times)
iex> end
["*", "*", "**", "*", "**", "***", "*", "**", "***", "****"]
(备注):可以拆解为:
iex(28)> for times <- 1..1 do String.duplicate("*",times) end ["*"] iex(29)> for times <- 1..2 do String.duplicate("*",times) end ["*", "**"] iex(30)> for times <- 1..3 do String.duplicate("*",times) end ["*", "**", "***"] iex(31)> for times <- 1..4 do String.duplicate("*",times) end ["*", "**", "***", "****"]
为了更好的说明正在执行的循环,我们使用 示例 两个被生成的值: IO.puts
iex> for n <- list, times <- 1..n, do: IO.puts "#{n} - #{times}"
1 - 1
2 - 1
2 - 2
3 - 1
3 - 2
3 - 3
4 - 1
4 - 2
4 - 3
4 - 4
列表解析是語法糖,只有在適當的時候才應該使用。
解析器(Filters)
可以把篩選器看作是解析式的监视 (guard)。當篩選值回傳 或 時,它將被排除在最終列表之外。让我们在一个范围内循环,并只注意偶數。我們將使用 Integer 模組中的 函數來檢查一個值是否是偶數。false
nil
is_even/1
import Integer
iex> for x <- 1..10, is_even(x), do: x
[2, 4, 6, 8, 10]
如同生成器 (generators),可以同時使用多個篩選器。現在擴展範圍,然後僅對偶數且可被 3 整除的值進行篩選。
import Integer
iex> for x <- 1..100,
...> is_even(x),
...> rem(x, 3) == 0, do: x
[6, 12, 18, 24, 30, 36, 42, 48, 54, 60, 66, 72, 78, 84, 90, 96]
使用 :into
如果想產生一個列表 (list) 以外的東西呢?加入 選項,就可以做到這一點!經驗上來說, 接受任何能實現 協定的結構。:into
:into
Collectable
要使用,让我们从关键字列表中建立一个映射: :into
iex> for {k, v} <- [one: 1, two: 2, three: 3], into: %{}, do: {k, v}
%{one: 1, three: 3, two: 2}
由於二進位 (binaries) 也是可群集 (collectables) 的,所以可以使用列表解析和 來建立字串::into
iex> for c <- [72, 101, 108, 108, 111], into: "", do: <<c>>
"Hello"
参考链接:
iex(1)> Enum.filter(["person.name", "person.email", "person.tel", "bot.name"], fn(x) ->
String.starts_with?(x, "person")
end)
["person.name", "person.email", "person.tel"]
# ## 列表解析comprehensions , elixir和erlang的语法 # for n <- [1, 2, 3, 4], do: n * n # [X * X || X <-lists:seq(1,4) ]