文档章节

elixir官方入门教程 推导式

ljzn
 ljzn
发布于 2016/08/05 22:12
字数 1314
阅读 42
收藏 0

#推导式

  1. 发生器和筛选器
  2. 位串生成器
  3. :into设置

在Elixir中,经常需要遍历一个枚举体,过滤掉一些结果,然后将值映射到另一个列表.推导式就是这种结构的语法糖:它将这些普遍的任务集合到for格式中.

例如,我们可以将一个整数列表映射到它们的平方:

iex> for n <- [1, 2, 3, 4], do: n * n
[1, 4, 9, 16]

一个推导式由三个部分组成:发生器,筛选器和收集器.

#发生器和筛选器

在上述表达式中,n <- [1, 2, 3, 4]是发生器.它会生成在推导式中使用的值.任何枚举体都可以被传送到发生器表达式的右边:

iex> for n <- 1..4, do: n * n
[1, 4, 9, 16]

生成器表达式的左边也支持模式匹配;所有不能匹配的都会被忽略.想象一下,表达式右边不再是一个范围,而是一个有着原子键:good:bad的关键词列表,而我们只想要计算:good值的平方:

iex> values = [good: 1, good: 2, bad: 3, good: 4]
iex> for {:good, n} <- values, do: n * n
[1, 4, 16]

除了模式匹配之外,筛选器可以用于选择一些特定的元素.例如,我们可以选出3的倍数:

iex> multiple_of_3? = fn(n) -> rem(n, 3) == 0 end
iex> for n <- 0..5, multiple_of_3?.(n), do: n * n
[0, 9]

推导式将所有筛选器表达式结果为falsenil的元素过滤掉了;其它所有值都被选入.

推导式通常提供比使用EnumStream模块中的相等函数更加简洁的表达方法.而且,推导式也允许指定多重生成器和筛选器.这里有一个例子,接收一个目录组成的列表,然后得到这些目录中每个文件的大小:

for dir  <- dirs,
    file <- File.ls!(dir),
    path = Path.join(dir, file),
    File.regular?(path) do
  File.stat!(path).size
end

多重发生器也可以用于计算两个列表的笛卡尔乘积:

iex> for i <- [:a, :b, :c], j <- [1, 2], do:  {i, j}
[a: 1, a: 2, b: 1, b: 2, c: 1, c: 2]

一个更好的关于多重发生器和筛选器的案例是勾股数.勾股数是指满足a*a + b*b = c*c的正整数,让我们在文件triple.exs中编写一个推导式:

defmodule Triple do
  def pythagorean(n) when n > 0 do
    for a <- 1..n,
        b <- 1..n,
        c <- 1..n,
        a + b + c <= n,
        a*a + b*b == c*c,
        do: {a, b, c}
  end
end

然后在终端中运行:

iex triple.exs
iex> Triple.pythagorean(5)
[]
iex> Triple.pythagorean(12)
[{3, 4, 5}, {4, 3, 5}]
iex> Triple.pythagorean(48)
[{3, 4, 5}, {4, 3, 5}, {5, 12, 13}, {6, 8, 10}, {8, 6, 10}, {8, 15, 17},
 {9, 12, 15}, {12, 5, 13}, {12, 9, 15}, {12, 16, 20}, {15, 8, 17}, {16, 12, 20}]

当搜索范围是一个巨大的数时,上述代码会非常昂贵.此外,由于{b, a, c}{a, b, c}是相同的勾股数,所以我们的函数生成重复结果.我们可以优化推导式来消除重复的结果,即在后面引用先前发生器中的变量,例如:

defmodule Triple do
  def pythagorean(n) when n > 0 do
    for a <- 1..n-2,
        b <- a+1..n-1,
        c <- b+1..n,
        a + b + c <= n,
        a*a + b*b == c*c,
        do: {a, b, c}
  end
end

最后,记住推导式内部的变量赋值,即发生器,筛选器或块内的,不会影响到推导式的外部.

#位串发生器

当你想要推导位串流的时候,位串发生器就非常有用了.下面的例子从一个二进制数中接收了一个由像素组成的列表,其中有他们的rgb值,然后将它们转换成了三元素元组:

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选项

在上述例子中,所有推导式都以列表作为返回值.然而,推导式的结果可以被插入不同的数据结构,通过传送:into选项给推导式.

例如,位串发生器可以和:into选项配合使用,来简单地消除字符串中的空格:

iex> for <<c <- " hello world ">>, c != ?\s, into: "", do: <<c>>
"helloworld"

集合,映射等其它的词典结构也可以被传递给:into选项.通常,:into接受可以实现Collectable协议的任何结构.

一个普遍的:into使用场景是不接触键,就能改变映射中的值:

iex> for {key, val} <- %{"a" => 1, "b" => 2}, into: %{}, do: {key, val * val}
%{"a" => 1, "b" => 4}

让我们看一个使用流的例子.因为IO模块提供了流(满足EnumerableCollectable),我们可以用推导式来实现一个返回输入内容的大写版本的回声终端:

iex> stream = IO.stream(:stdio, :line)
iex> for line <- stream, into: stream do
...>   String.upcase(line) <> "\n"
...> end

现在输入任意字符到终端中,你会看到相应的大写值打印出来.不幸的是,这个例子会使你的IEx壳陷入推导式中,所以你需要敲击两次Ctrl+C来退出它.:)

© 著作权归作者所有

共有 人打赏支持
ljzn
粉丝 29
博文 69
码字总数 96245
作品 0
南平
程序员
私信 提问
Elixir 学习资源

Elixir 官网 getting started官方入门学习资源 官方文档 hex 包管理系统 elixir sips 比较不错视频课程 Elixir China 中文论坛 官方wiki Elixir by Example Awesome Elixir Elixir Quiz 通过...

lidashuang
2017/11/29
0
0
总有你要的编程书单(GitHub )

目录 IDE IntelliJ IDEA 简体中文专题教程 MySQL 21分钟MySQL入门教程 MySQL索引背后的数据结构及算法原理 NoSQL Disque 使用教程 Neo4j .rb 中文資源 Redis 命令参考 Redis 设计与实现 The ...

汇智网
2017/11/22
0
0
elixir官方入门教程 介绍

介绍 安装 交互模式 运行脚本 提出疑问 欢迎! 在本教程中我们将教给你Elixir的基础,语法,如何定义模块,如何操作常用数据结构的特性等等.本章将确保Elixir安装好了,并且你能够成功运行Elixir的...

ljzn
2016/08/06
70
0
elixir官方入门教程 学习资料

下一步该去哪 构建你的第一个Elixir项目 元编程 社区与其它资源 Erlang基础 想要学习更多?继续阅读! 构建你的第一个Elixir项目 为了开始你的第一个项目,Elixir装载了一个叫做Mix的构建工具....

ljzn
2016/08/06
144
0
elixir官方教程Mix与OTP(一) Mix入门

Mix入门 我们的第一个项目 编辑项目 执行测试 环境 探索 在本教程中,我们将学习如何构建一个完整的Elixir应用,包括监督树,配置,测试等等. 这个应用的功能是分布式键值仓库.我们将把键值对安排...

ljzn
2016/08/07
1K
2

没有更多内容

加载失败,请刷新页面

加载更多

《货币商人》读后感作文选登3800字

《货币商人》读后感作文选登3800字: 领导之法、管理之术的大智慧与小技巧(宝安支行纪委书记葛希) 非常感谢夏书记向我们推荐了这本《货币商人》。这本书我读第一遍时惊现它像一个宝藏,蕴藏...

原创小博客
26分钟前
0
0
面试之ssm粗略简答

说实在的,spring源码对我来说可能就是报错的时候会一个个点进去找错误源头,其他都是为了让自己学习大神们优秀的编程思想和理念(顺便面试的时候吹吹牛皮~) 这次zhjj就直接抛了一个范围很...

无极之岚
27分钟前
1
0
史上最强Dubbo面试25题含答案详解:核心组件+架构设计+服务治理等

1.Dubbo是什么? Dubbo 是一个分布式、高性能、透明化的 RPC 服务框架,提供服务自动注册、自动发现等高效服务治理方案, 可以和 Spring 框架无缝集成。 RPC 指的是远程调用协议,也就是说两...

mikechen优知
51分钟前
0
0
如何正确的选择云数据库?

本文由云+社区发表 作者:数据库 江湖传说在选择和使用云数据库过程中 10个人有9个会遇到以下问题: 数据库正常使用过程中莫名卡顿 经常遭遇主从延迟和主从不一致 不知如何实现无损跨云跨数据...

腾讯云加社区
52分钟前
0
0
虚拟机下centos7.x简易命令大全与试玩体验

OS: liunx version: centos7.x date: 2019-01-18 1. cd / : 进入服务器根目录 2. cd .. : 进入当前目录的上一级 3. ls : 显示当前目录下的所有文件夹或文件(list的缩写) 4. ip addr : 展示服...

皇冠小丑
今天
0
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部