Julia Language
イーターラブル
サーチ…
構文
- 開始(itr)
- 次の(itr、s)
- done(itr、s)
- take(itr、n)
- ドロップ(itr、n)
- サイクル(itr)
- Base.product(xs、ys)
パラメーター
パラメータ | 詳細 |
---|---|
にとって | すべての関数 |
itr | 操作を繰り返すことができます。 |
にとって | next とdone |
s | 反復の現在の位置を記述する反復子状態。 |
にとって | take アンド・drop |
n | 取得または削除する要素の数。 |
にとって | Base.product |
xs | ペアの最初の要素を取るための反復可能性。 |
ys | ペアの第2要素を取る反復可能性。 |
... | ( product は任意の数の引数を受け付けることに注意してください; 2つ以上のものが提供される場合は、2つ以上の長さのタプルが作成されます)。 |
新しい反復可能な型
Juliaでは、反復可能なオブジェクトI
ループするとき、 for
構文で終わります:
for i = I # or "for i in I" # body end
背後には、これは次のように翻訳されています。
state = start(I) while !done(I, state) (i, state) = next(I, state) # body end
したがって、 I
が反復可能であることを望むなら、その型に対してstart
、 next
およびdone
メソッドを定義する必要があります。フィールドの1つとして配列を含む型 Foo
を定義するとします:
type Foo bar::Array{Int,1} end
以下のようにしてFoo
オブジェクトをインスタンス化します。
julia> I = Foo([1,2,3])
Foo([1,2,3])
julia> I.bar
3-element Array{Int64,1}:
1
2
3
Foo
を反復したい場合は、各要素のbar
が各繰り返しで返されるように、メソッドを定義します。
import Base: start, next, done start(I::Foo) = 1 next(I::Foo, state) = (I.bar[state], state+1) function done(I::Foo, state) if state == length(I.bar) return true end return false end
これらの関数はBase
モジュールに属しているので、新しいメソッドを追加する前に名前をimport
する必要があります。
メソッドが定義された後、 Foo
はイテレーター・インターフェースと互換性があります。
julia> for i in I println(i) end 1 2 3
遅延レイターを組み合わせる
標準ライブラリには、怠惰なイテラブルの豊富なコレクションが付属しています( Iterators.jlなどのライブラリではさらに多くの機能が提供されています)。遅いiterablesは、より強力なiterablesを一定の時間に作成するように構成することができます。最も重要な遅延型のiterablesはtakeとdropです 。そこから他の多くの関数を作成できます。
怠惰に繰り返し可能なスライス
配列はスライス表記でスライスできます。たとえば、配列の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]
"α"
任意のiterableでこの種のスライシングを行うために関数lazysub(itr, range::UnitRange)
を定義することができます。これはtake
とdrop
観点から定義されていdrop
。
lazysub(itr, r::UnitRange) = take(drop(itr, first(r) - 1), last(r) - first(r) + 1)
UnitRange
値a:b
場合、次の手順が実行されるため、ここでの実装が行われます。
- 最初の
a-1
要素を削除します。 -
a+(ba)=b
番目の要素までa
番目の要素、a+1
番目の要素などを取ります
合計で、 ba
要素が取られます。上記のそれぞれのケースで、実装が正しいことを確認できます。
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
それは円であるかのようにアレイ上の動作は、それをrelinearize、アレイをシフトします。例えば、
julia> circshift(1:10, 3)
10-element Array{Int64,1}:
8
9
10
1
2
3
4
5
6
7
私たちはすべてのiterablesのためにこれをゆっくりと行うことができますか?我々は使用することができcycle
、 drop
、およびtake
この機能を実装するために反復可能オブジェクトを。
lazycircshift(itr, n) = take(drop(cycle(itr), length(itr) - n), length(itr))
多くの状況で遅延型がよりcircshift
的であることに加えて、そうしなければそれをサポートしない型に対して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"
乗算表の作成
lazy iterable関数を使って行列を作る乗算表を作ってみましょう。
ここで使用する主な機能は次のとおりです。
解決策は次のとおりです。
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
遅延評価リスト
変更可能な型とクロージャを使用して単純な遅延評価リストを作成することは可能です。遅延評価リストは、構成時に評価されず、アクセスされたときに評価されるリストです。遅延評価リストの利点には、無限になる可能性が含まれます。
import Base: getindex
type Lazy
thunk
value
Lazy(thunk) = new(thunk)
end
evaluate!(lazy::Lazy) = (lazy.value = lazy.thunk(); lazy.value)
getindex(lazy::Lazy) = isdefined(lazy, :value) ? lazy.value : evaluate!(lazy)
import Base: first, tail, start, next, done, iteratorsize, HasLength, SizeUnknown
abstract List
immutable Cons <: List
head
tail::Lazy
end
immutable Nil <: List end
macro cons(x, y)
quote
Cons($(esc(x)), Lazy(() -> $(esc(y))))
end
end
first(xs::Cons) = xs.head
tail(xs::Cons) = xs.tail[]
start(xs::Cons) = xs
next(::Cons, xs) = first(xs), tail(xs)
done(::List, ::Cons) = false
done(::List, ::Nil) = true
iteratorsize(::Nil) = HasLength()
iteratorsize(::Cons) = SizeUnknown()
すべてのリストが遅延評価されているHaskellのような言語で実際に動作するもの:
julia> xs = @cons(1, ys)
Cons(1,Lazy(false,#3,#undef))
julia> ys = @cons(2, xs)
Cons(2,Lazy(false,#5,#undef))
julia> [take(xs, 5)...]
5-element Array{Int64,1}:
1
2
1
2
1
実際には、 Lazy.jlパッケージを使用する方が良いでしょう。しかし、上記の遅延リストの実装は、自身の反復可能な型を構築する方法についての重要な詳細を明示しています。