原副标题:向 for 循环式说“不”!
摘要:在责任编辑中,他们一起来掀开插值循环式的盖头,并如是说很多能全然替代插值的程式设计基本概念。
链接:https://medium.com/codex/ive-almost-stopped-using-iteration-entirely-ee34f208d7ad
译者 | Emmett Boudreau
翻译者 | 弯月 白眉林 | 郑丽媛
公司出品 | CSDN(ID:CSDNnews)
在撰写应用软件时,他们时常须要采用包涵相同类别的统计数据,此种统计数据一般来说被称作“内部结构”。更广义地说,很多某一类别的内部结构又称作“可插值第一类”。
可插值第一类是一类类别,其中包涵名为“原素”的统计数据类别,而不是表头或特性。举个范例,Julia 中的可插值第一类主要包括 Dict 和 Vector,就相等于 Python 中的 list 和 dict。Dict 包涵 Pair 类别的原素,而 Vector 包涵其模块选定的任意类别。这些类别的内部结构被称作“可插值第一类”,即使它是可以插值。
插值是程式设计中的一个十分关键性的基本概念。实际上,插值十分关键,就连合情理编订标识符中都包涵近似于循环式的同时实现。插值,更广义地说,for 循环式,是他们在自学因节程式设计语言时自学的第二个习题。不过,插值也有其另一方面的很多难题。
很多民主化的继续执行速率减缓,其原因最小的心理障碍常常就是循环式。因而,他们如果最小限度地提升循环式的操控性,防止冗余,并尽量防止循环式。那么,为何他们要将循环式做为预设的形式众所周知呢?为何不试一试其它有利于提升操控性的形式呢?
防止采用循环式
有几种技巧可以防止采用循环式。首先是递归,不过递归的应用范围更窄,而且操控性远远比不上循环式。不过,第二种方法就比较实用了。此种方法叫做“广播”(broadcasting),它将一个函数应用到给定内部结构中的每个原素上,因而可以很容易地一次性改变多个原素。还有一个类似的基本概念“映射”(mapping),从某种意义上来说,它和广播十分相似。第三种方法与它相似,叫做“解析式”(comprehension)。这几个基本概念的基本思想都是将一个函数应用到所有原素上,从而在多个值上同时进行某种运算。
在撰写 Python 时,最常用的方法就是 map。为了映射一个函数,他们只需用 lambda 或 def 定义它:
myfunc= lambda x: x + 1然后将这个函数传递给 map 函数,后者将返回一个 map 对象。map 函数的第二个模块是上述函数,第二个模块是要映射的 list。
map(myfunc, [ 1, 2, 3, 4, 5]) < mapobject at 0x7f33562f8fa0> list( map(myfunc, [ 1, 2, 3, 4, 5])) [ 2, 3, 4, 5, 6]虽然 Python 中的解析式也很强大,但与 Julia 等语言相比,其功能还是太受限了。因而,大部分情况下,解析式是快速操作多个原素的最佳选择。但是,由于解析式十分善于进行小型操作(如上例),他们如果在这里演示一下。
vals = [x + 1 forx in[1, 2, 3, 4, 5]] print(vals) [2, 3, 4, 5, 6]Julia 也有 map 函数,而且像 Python 一样,该函数十分易于采用。不过我必须承认,我在 Julia 中采用 map 的次数远远少于广播以及更强大的解析式。Julia 的 map 的语法也和 Python 十分相似,最主要的区别就是它会返回一个 Vector:
julia>map(x -> x + 1, [1, 2, 3, 4, 5, 6]) 6-element Vector{Int64}: 2 3 4 5 6 7Julia 也支持广播。与 map 很相似,他们可以利用广播在数组内的每个原素上应用任一函数。Python 的 NumPy 也提供了此功能,但是责任编辑主要想讨论 Julia。在 Julia 中,只需在给定函数前写一个点(.), 即可将其应用到每个原素。Julia 的基本操作符中时常被引用的一个示例如下:
x = [5, 10, 15] y = [5, 10, 15] x .* y 3-element Vector{Int64}: 25 100 225对于其它通用的应用,该操作也可以采用 @. 宏完成。如果你想了解有关 Julia 中广播的更多信息,可以阅读这篇文章:https://medium.com/chifi-media/broadcasting-power-in-julia-beginner-friendly-overview-11cdd099623a。
像 Python 一样,Julia 也有解析式。虽然 Python 的解析式很有局限性,特别是其可读性并非太好,但 Julia 则截然相同。当然,没有任何规定组禁止你在 Python 的解析式之外定义函数,但这样做会导致很多难题,比如当须要在函数中引某个变量的时候就会很麻烦。尽管如此,虽然有时候 Python 的解析式须要借助其它东西才能清晰易读,但 Julia 的解析式可以像函数一样书写,可以写在多行内,而且支持多种语句!下面是一个解析式,它很像 Python:
x = [x – 1forx in1: 5]替代循环式
下面,他们来看看 Julia 的解析式究竟好在哪里。首先,他们可以利用 begin/end 语法,以函数的形式撰写解析式。
x = [ beginx – 1endforx in1:5]在解析式中添加 begin/end 敞开了一扇大门,可以让解析式完成更多的工作。我喜欢将解析式写成这样:
x = [ begin x – 1 endforx in1:5]在这个新函数中,他们可以做任何循环式能做的事情,除了很多例外。例如,下面是个条件语句:
julia> x = [ begin ifx > 1 5 else 3 end endforx in1:10] 10-element Vector{Int64}: 3 5 5 5 5 5 5 5 5 5虽然 Python 也能同时实现这一点,但别忘了,他们还能添加更多的语句,甚至可以采用 try/catch 和闭包!
julia> x = [begin ifx > 1 5 else try “hello”* 5 catch 3 end end endforx in1: 10] 10-element Vector{Int64}: 3 5 5 5 5 5 5 5 5 5须要循环式的情况
虽然用函数替换循环式能节省不少时间,但循环式在程式设计语言和应用软件中依然有着关键的作用。最值得一提的是,循环式的关键性字 break 和 continue 是其它方法都没有的。这可以节省很多不必要的循环式。break 关键性字能结束循环式,而 continue 关键性字可以直接跳转到下一次循环式。下面是选择循环式的一个范例,主要目的是在找到适当的值时,利用 break 跳出循环式:
function display(d::OliveDisplay, m::MIME{<:Any}, o::Any) T::Type = typeof(o) mymimes = [MIME “text/html”, MIME“text/svg”, MIME “text/plain”] mmimes = [m.sig.parameters[ 3] form inmethods(show, [IO, Any, T])] correctm = nothing form inmymimes ifm inmmimes correctm = m break end end show(d.io, correctm, o) end在这个范例中,他们依次遍历 MIME,找到最有可能的值。在已有的 MIME(即 mmimes)中找到所需的 mime 后,设置 correctm,然后将其传递给 show 函数。这个范例中,相较于映射或解析式,选择插值更合适,因为它拥有独到的优势。
总结
一直以来,插值式循环式都是程式设计中的一个关键的基本概念,在高级语言中得到了广泛的应用。循环式是从硬件层面上同时实现的,其关键性不言而喻。但是,很多现代程式设计语言全然可以不采用循环式,他们可以利用函数、映射和解析式来同时实现相同的功能。但是,在有很多情况下,选择循环式依然比解析式或映射更好。一类情况就是可以利用 break 和 continue 关键性字跳过原素、加快循环式。
☞ 雷军回应对标iPhone被笑话:没勇气就做不好高端手机;GitHub发布企业版Copilot;Linux 6.1 发布|极客头条
☞ 47 岁从华为退休,操作系统老兵转战 OpenHarmony 生态 | 近匠
☞“CSDN 2022 中国开发者影响力年度评选”正式开启报名!