在本文中,我们将介绍 Python 中 for 循环和推导式的一些常见用法,如何分析现有循环,以及如何将它们转换为 Elixir 中的等效表达式,使用 Enum 模块和 推导式.
中的函数我们将重点关注:
我们将以一个结合了这三者的基本示例来结束!
在 Python 中,for 循环 通常具有交错处理功能 - 这些步骤被组合在一起形成相同的子句或主体。下面是前两个偶数的平方的示例:
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
结果 - 步骤顺序是:
推导式 是映射 和过滤 集合(如列表和字典)的简单方法。它们没有提供减少结果的方法,但是我们可以使用诸如 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 代码!
我们如何将步长写成平方数?在 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(或 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/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)
此处进行两项更改:
作为一般规则,我们应该以尽可能最高级别的方式表达我们想要转换的数据。将 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:形式尽管级别较低,但实际上阅读起来更清晰。
总而言之,我们最终得到了两种可以被认为是惯用的形式。对于枚举管道:
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
易于阅读的代码应该能够直接浏览,没有歧义或在表达式上结结巴巴。我认为这两种形式都符合该标准,如:
在 Elixir 中可以通过多种不同的方式来编写这些转换,并且代码库很容易改变样式,特别是当代码发生更改且处理随着时间的推移变得更加复杂时。
PureType 可以分解和分析枚举管道和推导式,以最清晰、最惯用的形式表示它们,了解您的偏好并提高代码对团队中其他人的可读性和清晰度。今天就尝试一下吧!
以上是Elixir 中的 For 循环和推导式 - 转换命令式代码的详细内容。更多信息请关注PHP中文网其他相关文章!