首页 > 后端开发 > Python教程 > Elixir 中的 For 循环和推导式 - 转换命令式代码

Elixir 中的 For 循环和推导式 - 转换命令式代码

Linda Hamilton
发布: 2024-12-04 15:05:11
原创
165 人浏览过

For loops and comprehensions in Elixir - transforming imperative code

在本文中,我们将介绍 Python 中 for 循环和推导式的一些常见用法,如何分析现有循环,以及如何将它们转换为 Elixir 中的等效表达式,使用 Enum 模块和 推导式.

中的函数

我们将重点关注:

  • 通过函数转换数据集合 (map)
  • 将值过滤到集合中或从集合中过滤出来(过滤器
  • 生成单个聚合值或结构,例如平均值(减少折叠

我们将以一个结合了这三者的基本示例来结束!

Python

For 循环

在 Python 中,for 循环 通常具有交错处理功能 - 这些步骤被组合在一起形成相同的子句或主体。下面是前两个偶数的平方的示例:

result = 0
for num in [1, 2, 3, 4, 5]:
    if num % 2 == 0:
        result += num ** 2
print(result)  # Output: 20
登录后复制
登录后复制
登录后复制

这个交错体的一个挑战是:

  1. 识别每个步骤,并且......
  2. 弄清楚它是什么类型的步骤。

分解每个步骤可以让您了解正在发生的转换,消除任何不必要的转换,并将这些步骤重写为另一种语言构造或更高级别的函数。

注释上面的函数会得到:

result = 0
for num in [1, 2, 3, 4, 5]:
    ## Filter
    if num % 2 == 0:
        ## Reduce (result += ) and Map (num ** 2)
        result += num ** 2
print(result)  # Output: 20
登录后复制
登录后复制
登录后复制

步骤

结果 - 步骤顺序是:

  1. 过滤“出”奇数/“入”偶数
  2. 数字(例如2)映射到其相应的平方数(例如4)
  3. 减少为偶数平方和

推导式

Python 中的

推导式映射过滤 集合(如列表和字典)的简单方法。它们没有提供减少结果的方法,但是我们可以使用诸如 sum 之类的内置函数来转换上面的函数来处理理解的结果:

result = sum(num ** 2 for num in [1, 2, 3, 4, 5] if num % 2 == 0)
print(result)  # Output: 20
登录后复制
登录后复制

通过推导式,表达式将 map 步骤 (num ** 2) 和 filter 步骤(如果 num % 2 == 0) 清楚。 sum 是此处的 reduce 步骤。

在 Python 中浏览这些推导式很容易,并且它为推导式的复杂性设置了有用的上限。

有了这个背景,并且更好地理解了 Python 处理构造的结构和限制,让我们继续使用 Elixir 的推导式和 Enum 管道重写上述 Python 代码!

映射:Enum.map 和生成器

我们如何将步长写成平方数?在 Elixir 中,这很简单!

使用 Enum.map:

result = 0
for num in [1, 2, 3, 4, 5]:
    if num % 2 == 0:
        result += num ** 2
print(result)  # Output: 20
登录后复制
登录后复制
登录后复制

并使用推导式(for):

result = 0
for num in [1, 2, 3, 4, 5]:
    ## Filter
    if num % 2 == 0:
        ## Reduce (result += ) and Map (num ** 2)
        result += num ** 2
print(result)  # Output: 20
登录后复制
登录后复制
登录后复制

生成器 表达式,生成要在 for 表达式主体中使用的值,在 do:

之后

过滤:Enum.filter和filters

使用 Enum.filter(或 Enum.reject)很容易做到:

result = sum(num ** 2 for num in [1, 2, 3, 4, 5] if num % 2 == 0)
print(result)  # Output: 20
登录后复制
登录后复制

我们希望在求平方之前过滤掉奇数,因此我们将其放置在管道中的正确位置 - 在 Enum.map 之前。

使用推导式,我们可以在推导式的头部添加第二个表达式,一个过滤器,它是一个布尔测试:

Enum.map([1, 2, 3, 4, 5], & &1 ** 2)
登录后复制

rem(n, 2) == 0 表达式会丢弃所有返回 false(或 nil)的元素,留下 [2, 4] 作为实际传递到主体的数字(do: n ** 2)的理解。

减少-> Enum.reduce和reduce:

使用 Enum.reduce/2,我们可以通过添加到累加器来将平方数列表转换为其总和。如果我们没有为累加器指定初始值 (Enum.reduce/3),第一个元素将用作累加器的初始值,这在这里很方便:

for n <- [1, 2, 3, 4, 5], do: n ** 2
登录后复制

通过推导式,我们比 Python 的同等功能更强大。我们可以通过在头部添加另一个子句来添加一个归约步骤:

[1, 2, 3, 4, 5]
|> Enum.filter(& rem(&1, 2) == 0)
|> Enum.map(& &1 ** 2)
登录后复制

此处进行两项更改:

  1. 在头部添加一个reduce: 0子句,指定我们将累加一个初始值为0的值
  2. 更改 for 主体以捕获 acc 值(累加器),我们可以将当前平方值添加到该值。

内置函数:Enum.sum

作为一般规则,我们应该以尽可能最高级别的方式表达我们想要转换的数据。将 Enum.reduce 视为最低级别的函数转换很有用,因为所有其他数据处理都可以用它来重写。

Enum 模块包含大量高级函数,通常涉及将值列表减少为单个聚合值,例如总和、最大值或最小值。在本例中,我们想要元素的总和。

对于枚举管道,这很简单:

for n <- [1, 2, 3, 4, 5], rem(n, 2) == 0, do: n ** 2
登录后复制

没有办法在推导式中表示这些高级聚合函数,因此我们可以将推导式的输出通过管道传输到 Enum.sum 调用中,类似于我们在 Python 中的做法:

[1, 2, 3, 4, 5]
|> Enum.filter(& rem(&1, 2) == 0)
|> Enum.map(& &1 ** 2)
|> Enum.reduce(& &1 + &2)
登录后复制

通常应该避免混合不同的形式,特别是如果转换是简单的,因为它会减轻读者的精神负担 - 上面的reduce:形式尽管级别较低,但实际上阅读起来更清晰。

Elixir 哪种表达方式更好?

总而言之,我们最终得到了两种可以被认为是惯用的形式。对于枚举管道:

result = 0
for num in [1, 2, 3, 4, 5]:
    if num % 2 == 0:
        result += num ** 2
print(result)  # Output: 20
登录后复制
登录后复制
登录后复制

和理解:

result = 0
for num in [1, 2, 3, 4, 5]:
    ## Filter
    if num % 2 == 0:
        ## Reduce (result += ) and Map (num ** 2)
        result += num ** 2
print(result)  # Output: 20
登录后复制
登录后复制
登录后复制

易于阅读的代码应该能够直接浏览,没有歧义或在表达式上结结巴巴。我认为这两种形式都符合该标准,如:

  1. 它们遵循单一一致的形式 - 枚举管道或推导式
  2. 每个表达式对应一个处理步骤
  3. 可以从上到下或从左到右不间断地阅读

结论

在 Elixir 中可以通过多种不同的方式来编写这些转换,并且代码库很容易改变样式,特别是当代码发生更改且处理随着时间的推移变得更加复杂时。

PureType 可以分解和分析枚举管道和推导式,以最清晰、最惯用的形式表示它们,了解您的偏好并提高代码对团队中其他人的可读性和清晰度。今天就尝试一下吧!

以上是Elixir 中的 For 循环和推导式 - 转换命令式代码的详细内容。更多信息请关注PHP中文网其他相关文章!

来源:dev.to
本站声明
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn
作者最新文章
热门教程
更多>
最新下载
更多>
网站特效
网站源码
网站素材
前端模板