Zoeken…


Syntaxis

  • start (ITR)
  • volgende (itr, s)
  • gedaan (itr, s)
  • nemen (itr, n)
  • neerzetten (itr, n)
  • cycle (ITR)
  • Base.product (xs, ys)

parameters

Parameter Details
Voor Alle functies
itr De iterabele om op te werken.
Voor next en done
s Een iterator die de huidige positie van de iteratie beschrijft.
Voor take en drop
n Het aantal elementen dat moet worden verwijderd of verwijderd.
Voor Base.product
xs De iterabele om eerste elementen van paren van te nemen.
ys De iterabele om tweede elementen van paren van te nemen.
... (Merk op dat het product willekeurig aantal argumenten accepteert; als er meer dan twee worden opgegeven, worden er tuples met een lengte van meer dan twee geconstrueerd.)

Nieuw iterabel type

In Julia, toen het doorlussen van een iterable object I is gedaan met de for syntax:

for i = I   # or  "for i in I"
    # body
end

Achter de schermen wordt dit vertaald naar:

state = start(I)
while !done(I, state)
    (i, state) = next(I, state)
    # body
end

Daarom, als je wilt dat I een iterabel ben, moet je de start , next en done methoden definiëren voor het type. Stel dat u een type Foo met een array definieert als een van de velden:

type Foo
    bar::Array{Int,1}
end

We instantiëren een Foo object door het volgende te doen:

julia> I = Foo([1,2,3])
Foo([1,2,3])

julia> I.bar
3-element Array{Int64,1}:
 1
 2
 3

Willen we parafraseren door middel van Foo , met elk element bar wordt geretourneerd door elke iteratie, definiëren we de methoden:

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

Aangezien deze functies tot de Base behoren, moeten we eerst hun namen import voordat we er nieuwe methoden aan toevoegen.

Nadat de methoden zijn gedefinieerd, is Foo compatibel met de iterator-interface:

julia> for i in I
           println(i)
       end

1
2
3

Lazy Iterables combineren

De standaardbibliotheek wordt geleverd met een rijke verzameling luie iterables (en bibliotheken zoals Iterators.jl bieden nog meer). Lazy iterables kunnen worden samengesteld om krachtigere iterables in constante tijd te creëren. De belangrijkste luie eters zijn take and drop , waaruit vele andere functies kunnen worden gemaakt.

Snijd een iterabel

Arrays kunnen worden gesneden met plaknotatie. Het volgende retourneert bijvoorbeeld de 10e tot 15e elementen van een array, inclusief:

A[10:15]

Segmentnotatie werkt echter niet met alle iterables. We kunnen bijvoorbeeld geen generator-expressie segmenteren:

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

Het snijden van strings kan niet het verwachte Unicode-gedrag:

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

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

We kunnen een functie lazysub(itr, range::UnitRange) om dit soort segmentatie op willekeurige iterables uit te voeren. Dit wordt gedefinieerd in termen van take and drop :

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

De implementatie werkt hier omdat voor UnitRange waarde a:b de volgende stappen worden uitgevoerd:

  • laat de eerste a-1 elementen vallen
  • neemt het a -element, a+1 -element, enzovoort, tot het a+(ba)=b -element

In totaal worden ba elementen genomen. We kunnen bevestigen dat onze implementatie in elk afzonderlijk geval correct is:

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

Verplaats een iterabele circulair lui

De circshift bewerking op arrays zal de array verschuiven alsof het een cirkel is en deze vervolgens opnieuw definiëren. Bijvoorbeeld,

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

Kunnen we dit lui doen voor alle iterables? We kunnen het gebruiken cycle , drop , en take iterables om deze functionaliteit te implementeren.

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

Samen met luie types die in veel situaties beter presteren, laat dit ons circshift achtige functionaliteit uitvoeren op types die het anders niet zouden ondersteunen:

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

Een vermenigvuldigingstabel maken

Laten we een vermenigvuldigingstabel maken met behulp van luie itereerbare functies om een matrix te maken.

De belangrijkste functies die u hier kunt gebruiken zijn:

  • Base.product , dat een Cartesiaans product berekent.
  • prod , die een regulier product berekent (zoals bij vermenigvuldiging)
  • : , waarmee een bereik wordt gemaakt
  • map , een hogere orde functie die een functie toepast op elk element van een verzameling

De oplossing is:

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

Lazily geëvalueerde lijsten

Het is mogelijk om een eenvoudige, lui geëvalueerde lijst te maken met behulp van veranderlijke typen en sluitingen . Een lui geëvalueerde lijst is een lijst waarvan de elementen niet worden geëvalueerd wanneer deze wordt samengesteld, maar eerder wanneer deze wordt geopend. Voordelen van lui geëvalueerde lijsten omvatten de mogelijkheid om oneindig te zijn.

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()

Dat werkt inderdaad zoals het zou doen in een taal als Haskell , waar alle lijsten lui worden geëvalueerd:

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

In de praktijk is het beter om het Lazy.jl- pakket te gebruiken. De implementatie van de luie lijst hierboven werpt echter belangrijke details op over hoe je een eigen iterabel type kunt bouwen.



Modified text is an extract of the original Stack Overflow Documentation
Licentie onder CC BY-SA 3.0
Niet aangesloten bij Stack Overflow