結合懶惰的 Iterables

標準庫附帶了大量惰性迭代(以及 Iterators.jl 等庫提供了更多)。可以組合延遲迭代以在恆定時間內建立更強大的迭代。最重要的延遲迭代是取放 ,從中可以建立許多其他函式。

懶惰切片一個可迭代的

可以使用切片表示法切割陣列。例如,以下內容返回陣列的第 10 個到第 15 個元素,包括:

A[10:15]

但是,切片表示法不適用於所有迭代。例如,我們不能切片生成器表示式:

julia> (i^2 for i in 1:10)[3:5]
ERROR: MethodError: no method matching getindex(::Base.Generator{UnitRange{Int64},##1#2}, ::UnitRange{Int64})

切片字串可能沒有預期的 Unicode 行為:

julia> "αααα"[2:3]
ERROR: UnicodeError: invalid character index
 in getindex(::String, ::UnitRange{Int64}) at ./strings/string.jl:130

julia> "αααα"[3:4]
"α"

我們可以定義一個函式 lazysub(itr, range::UnitRange) 來對任意迭代進行這種切片。這是根據 takedrop 定義的:

lazysub(itr, r::UnitRange) = take(drop(itr, first(r) - 1), last(r) - first(r) + 1)

這裡的實現有效,因為對於 UnitRangea:b,執行以下步驟:

  • 放下第一個 a-1 元素
  • ath 元素,a+1th 元素,等等,直到 a+(b-a)=bth 元素

總共採用了 b-a 元素。我們可以在上面的每種情況下確認我們的實施是否正確

julia> collect(lazysub("αααα", 2:3))
2-element Array{Char,1}:
 'α'
 'α'

julia> collect(lazysub((i^2 for i in 1:10), 3:5))
3-element Array{Int64,1}:
  9
 16
 25

懶惰地迴圈移動

對陣列的 circshift 操作將使陣列移位,就像它是一個圓,然後重新線性化它。例如,

julia> circshift(1:10, 3)
10-element Array{Int64,1}:
  8
  9
 10
  1
  2
  3
  4
  5
  6
  7

我們可以懶洋洋地為所有迭代事件做這件事嗎?我們可以使用 cycledroptake iterables 來實現此功能。

lazycircshift(itr, n) = take(drop(cycle(itr), length(itr) - n), length(itr))

隨著懶惰型別在許多情況下的效能更高,這使我們可以在不支援它的型別上執行類似 circshift 的功能:

julia> circshift("Hello, World!", 3)
ERROR: MethodError: no method matching circshift(::String, ::Int64)
Closest candidates are:
  circshift(::AbstractArray{T,N}, ::Real) at abstractarraymath.jl:162
  circshift(::AbstractArray{T,N}, ::Any) at abstractarraymath.jl:195

julia> String(collect(lazycircshift("Hello, World!", 3)))
"ld!Hello, Wor"

Version >= 0.5.0

製作乘法表

讓我們使用惰性可迭代函式建立一個乘法表來建立一個矩陣。

這裡使用的關鍵功能是:

  • Base.product,計算笛卡爾積
  • prod,計算常規產品(如乘法)
  • :,它創造了一個範圍
  • map ,這是一個將函式應用於集合的每個元素的高階函式

解決方案是:

julia> map(prod, Base.product(1:10, 1:10))
10×10 Array{Int64,2}:
  1   2   3   4   5   6   7   8   9   10
  2   4   6   8  10  12  14  16  18   20
  3   6   9  12  15  18  21  24  27   30
  4   8  12  16  20  24  28  32  36   40
  5  10  15  20  25  30  35  40  45   50
  6  12  18  24  30  36  42  48  54   60
  7  14  21  28  35  42  49  56  63   70
  8  16  24  32  40  48  56  64  72   80
  9  18  27  36  45  54  63  72  81   90
 10  20  30  40  50  60  70  80  90  100