サーチ…


構文

  • 開始(itr)
  • 次の(itr、s)
  • done(itr、s)
  • take(itr、n)
  • ドロップ(itr、n)
  • サイクル(itr)
  • Base.product(xs、ys)

パラメーター

パラメータ詳細
にとって すべての関数
itr 操作を繰り返すことができます。
にとって nextdone
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が反復可能であることを望むなら、その型に対してstartnextおよび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)を定義することができます。これはtakedrop観点から定義されていdrop

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

UnitRangea: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のためにこれをゆっくりと行うことができますか?我々は使用することができcycledrop 、および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"
0.5.0

乗算表の作成

lazy iterable関数を使って行列を作る乗算表を作ってみましょう。

ここで使用する主な機能は次のとおりです。

  • 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

遅延評価リスト

変更可能な型とクロージャを使用して単純な遅延評価リストを作成することは可能です。遅延評価リストは、構成時に評価されず、アクセスされたときに評価されるリストです。遅延評価リストの利点には、無限になる可能性が含まれます。

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パッケージを使用する方が良いでしょう。しかし、上記の遅延リストの実装は、自身の反復可能な型を構築する方法についての重要な詳細を明示しています。



Modified text is an extract of the original Stack Overflow Documentation
ライセンスを受けた CC BY-SA 3.0
所属していない Stack Overflow