Julia Language
terwijl Loops
Zoeken…
Syntaxis
- terwijl cond; lichaam; einde
- breken
- doorgaan met
Opmerkingen
De while
lus heeft geen waarde; hoewel het in de expressiepositie kan worden gebruikt, is het type Void
en is de verkregen waarde nothing
.
Collatz-reeks
De while
lus loopt door zijn lichaam zolang de toestand van kracht is. Met de volgende code wordt bijvoorbeeld de Collatz-reeks berekend en afgedrukt vanaf een bepaald nummer:
function collatz(n)
while n ≠ 1
println(n)
n = iseven(n) ? n ÷ 2 : 3n + 1
end
println("1... and 4, 2, 1, 4, 2, 1 and so on")
end
Gebruik:
julia> collatz(10)
10
5
16
8
4
2
1... and 4, 2, 1, 4, 2, 1 and so on
Het is mogelijk om elke lus recursief te schrijven, en voor complexe while
lussen is de recursieve variant soms duidelijker. In Julia hebben loops echter een aantal duidelijke voordelen ten opzichte van recursie:
- Julia garandeert geen eliminatie van staartoproepen, dus recursie gebruikt extra geheugen en kan stapeloverloopfouten veroorzaken.
- En verder, om dezelfde reden, kan een lus minder overhead hebben en sneller lopen.
Voer één keer uit voordat de conditie wordt getest
Soms wil men eenmaal een initialisatiecode uitvoeren voordat een voorwaarde wordt getest. In bepaalde andere talen heeft dit soort lus een speciale do
- while
syntaxis. Deze syntaxis kan echter worden vervangen door een reguliere while
lus en break
instructie, dus Julia heeft geen gespecialiseerde do
- while
syntaxis. In plaats daarvan schrijft men:
local name
# continue asking for input until satisfied
while true
# read user input
println("Type your name, without lowercase letters:")
name = readline()
# if there are no lowercase letters, we have our result!
!any(islower, name) && break
end
Merk op dat in sommige situaties dergelijke lussen duidelijker kunnen zijn met recursie:
function getname()
println("Type your name, without lowercase letters:")
name = readline()
if any(islower, name)
getname() # this name is unacceptable; try again
else
name # this name is good, return it
end
end
Breedte-eerste zoekopdracht
(Hoewel dit voorbeeld is geschreven met behulp van syntaxis geïntroduceerd in versie v0.5, kan het ook met enkele wijzigingen werken op oudere versies.)
Deze implementatie van breedte-eerste zoekopdracht (BFS) in een grafiek die wordt weergegeven met aangrenzende lijsten maakt gebruik van while
lussen en de return
instructie. De taak die we zullen oplossen is als volgt: we hebben een opeenvolging van mensen en een opeenvolging van vriendschappen (vriendschappen zijn wederzijds). We willen de mate van verbinding tussen twee mensen bepalen. Dat wil zeggen, als twee mensen vrienden zijn, zullen we 1
teruggeven; als de een vriend is van een vriend van de ander, zullen we 2
teruggeven, enzovoort.
Laten we eerst aannemen dat we al een aangrenzende lijst hebben: een Dict
T
aan Array{T, 1}
, waarbij de sleutels mensen zijn en de waarden alle vrienden van die persoon zijn. Hier kunnen we mensen vertegenwoordigen met het type T
we kiezen; in dit voorbeeld gebruiken we Symbol
. In het BFS-algoritme houden we een rij mensen bij om te 'bezoeken' en markeren ze hun afstand tot het oorspronkelijke knooppunt.
function degree(adjlist, source, dest)
distances = Dict(source => 0)
queue = [source]
# until the queue is empty, get elements and inspect their neighbours
while !isempty(queue)
# shift the first element off the queue
current = shift!(queue)
# base case: if this is the destination, just return the distance
if current == dest
return distances[dest]
end
# go through all the neighbours
for neighbour in adjlist[current]
# if their distance is not already known...
if !haskey(distances, neighbour)
# then set the distance
distances[neighbour] = distances[current] + 1
# and put into queue for later inspection
push!(queue, neighbour)
end
end
end
# we could not find a valid path
error("$source and $dest are not connected.")
end
Nu zullen we een functie schrijven om een aangrenzende lijst samen te stellen met een reeks mensen en een reeks (person, person)
tupels:
function makeadjlist(people, friendships)
# dictionary comprehension (with generator expression)
result = Dict(p => eltype(people)[] for p in people)
# deconstructing for; friendship is mutual
for (a, b) in friendships
push!(result[a], b)
push!(result[b], a)
end
result
end
We kunnen nu de oorspronkelijke functie definiëren:
degree(people, friendships, source, dest) =
degree(makeadjlist(people, friendships), source, dest)
Laten we nu onze functie op enkele gegevens testen.
const people = [:jean, :javert, :cosette, :gavroche, :éponine, :marius]
const friendships = [
(:jean, :cosette),
(:jean, :marius),
(:cosette, :éponine),
(:cosette, :marius),
(:gavroche, :éponine)
]
Jean is in 0
stappen met zichzelf verbonden:
julia> degree(people, friendships, :jean, :jean)
0
Jean en Cosette zijn vrienden, en hebben dus ook graad 1
:
julia> degree(people, friendships, :jean, :cosette)
1
Jean en Gavroche zijn indirect verbonden via Cosette en vervolgens Marius, dus hun graad is 3
:
julia> degree(people, friendships, :jean, :gavroche)
3
Javert en Marius zijn via geen enkele ketting verbonden, dus er is een fout opgetreden:
julia> degree(people, friendships, :javert, :marius)
ERROR: javert and marius are not connected.
in degree(::Dict{Symbol,Array{Symbol,1}}, ::Symbol, ::Symbol) at ./REPL[28]:27
in degree(::Array{Symbol,1}, ::Array{Tuple{Symbol,Symbol},1}, ::Symbol, ::Symbol) at ./REPL[30]:1