Elixir语言中 Kernel.SpecialForms.for
相关用法介绍如下。
用法:
for(args)
(宏)
理解允许您从可枚举或位串快速构建数据结构。
让我们从一个例子开始:
iex> for n <- [1, 2, 3, 4], do: n * 2
[2, 4, 6, 8]
推导式接受许多生成器和过滤器。可枚举生成器使用 <-
定义:
# A list generator:
iex> for n <- [1, 2, 3, 4], do: n * 2
[2, 4, 6, 8]
# A comprehension with two generators
iex> for x <- [1, 2], y <- [2, 3], do: x * y
[2, 3, 4, 6]
也可以给出过滤器:
# A comprehension with a generator and a filter
iex> for n <- [1, 2, 3, 4, 5, 6], rem(n, 2) == 0, do: n
[2, 4, 6]
生成器也可用于过滤,因为它会删除与 <-
左侧的模式不匹配的任何值:
iex> users = [user: "john", admin: "meg", guest: "barbara"]
iex> for {type, name} when type != :guest <- users do
...> String.upcase(name)
...> end
["JOHN", "MEG"]
位串生成器也受支持,并且在您需要组织位串流时非常有用:
iex> pixels = <<213, 45, 132, 64, 76, 32, 76, 0, 0, 234, 32, 15>>
iex> for <<r::8, g::8, b::8 <- pixels>>, do: {r, g, b}
[{213, 45, 132}, {64, 76, 32}, {76, 0, 0}, {234, 32, 15}]
理解内的变量赋值,无论是在生成器、过滤器还是块内,都不会反映在理解之外。
:into
和 :uniq
选项
在上面的示例中,推导式返回的结果始终是一个列表。返回的结果可以通过传递 :into
选项来配置,只要它实现
协议,它就可以接受任何结构。Collectable
例如,我们可以使用带有:into
选项的位串生成器来轻松删除字符串中的所有空格:
iex> for <<c <- " hello world ">>, c != ?\s, into: "", do: <<c>>
"helloworld"
模块提供流,它们都是 IO
和 Enumerable
,这是一个使用理解的大写回显服务器:Collectable
for line <- IO.stream(), into: IO.stream() do
String.upcase(line)
end
类似地,uniq: true
也可以用于理解,以保证只有在之前没有返回结果的情况下才会将结果添加到集合中。例如:
iex> for x <- [1, 1, 2, 3], uniq: true, do: x * 2
[2, 4, 6]
iex> for <<x <- "abcabc">>, uniq: true, into: "", do: <<x - 32>>
"ABC"
:reduce
选项
虽然:into
选项允许我们自定义对给定数据类型的理解行为,例如将所有值放入映射或二进制文件中,但这并不总是足够的。
例如,假设您有一个带有字母的二进制文件,您想计算每个小写字母出现的次数,忽略所有大写字母。例如,对于字符串 "AbCabCABc"
,我们要返回映射 %{"a" => 1, "b" => 2, "c" => 1}
。
如果我们要使用 :into
,我们需要一个数据类型来计算它所拥有的每个元素的频率。虽然 Elixir 中没有这样的数据类型,但您可以自己实现一个。
一个更简单的选择是对字母的映射和过滤使用理解,然后我们调用
来构建一个映射,例如:Enum.reduce/3
iex> letters = for <<x <- "AbCabCABc">>, x in ?a..?z, do: <<x>>
iex> Enum.reduce(letters, %{}, fn x, acc -> Map.update(acc, x, 1, & &1 + 1) end)
%{"a" => 1, "b" => 2, "c" => 1}
虽然上面是straight-forward,但它的缺点是至少要遍历数据两次。如果您期望长字符串作为输入,这可能会非常昂贵。
幸运的是,推导式也支持 :reduce
选项,这将允许我们将上述两个步骤融合为一个步骤:
iex> for <<x <- "AbCabCABc">>, x in ?a..?z, reduce: %{} do
...> acc -> Map.update(acc, <<x>>, 1, & &1 + 1)
...> end
%{"a" => 1, "b" => 2, "c" => 1}
当给定:reduce
键时,其值用作初始累加器,必须将do
块更改为使用->
子句,其中->
的左侧接收上一次迭代的累加值,右侧的表达式必须返回新的累加器值。一旦没有更多元素,则返回最终的累加值。如果根本没有元素,则返回初始累加器值。
相关用法
- Elixir Kernel.SpecialForms.fn用法及代码示例
- Elixir Kernel.SpecialForms.case用法及代码示例
- Elixir Kernel.SpecialForms.%{}用法及代码示例
- Elixir Kernel.SpecialForms.quote用法及代码示例
- Elixir Kernel.SpecialForms.require用法及代码示例
- Elixir Kernel.SpecialForms.&expr用法及代码示例
- Elixir Kernel.SpecialForms.<<args>>用法及代码示例
- Elixir Kernel.SpecialForms.{args}用法及代码示例
- Elixir Kernel.SpecialForms.unquote_splicing用法及代码示例
- Elixir Kernel.SpecialForms.receive用法及代码示例
- Elixir Kernel.SpecialForms.%struct{}用法及代码示例
- Elixir Kernel.SpecialForms.import用法及代码示例
- Elixir Kernel.SpecialForms.left . right用法及代码示例
- Elixir Kernel.SpecialForms.alias用法及代码示例
- Elixir Kernel.SpecialForms.try用法及代码示例
- Elixir Kernel.SpecialForms.cond用法及代码示例
- Elixir Kernel.SpecialForms.__aliases__用法及代码示例
- Elixir Kernel.SpecialForms.left :: right用法及代码示例
- Elixir Kernel.SpecialForms.unquote用法及代码示例
- Elixir Kernel.SpecialForms.with用法及代码示例
- Elixir Kernel.SpecialForms.__block__用法及代码示例
- Elixir Kernel.SpecialForms.^var用法及代码示例
- Elixir Kernel.round用法及代码示例
- Elixir Kernel.left / right用法及代码示例
- Elixir Kernel.put_in用法及代码示例
注:本文由纯净天空筛选整理自elixir-lang.org大神的英文原创作品 Kernel.SpecialForms.for(args)。非经特殊声明,原始代码版权归原作者所有,本译文未经允许或授权,请勿转载或复制。