Julia Language
mentre cicli
Ricerca…
Sintassi
- mentre cond; corpo; fine
- rompere
- Continua
Osservazioni
Il ciclo while
non ha un valore; sebbene possa essere usato nella posizione dell'espressione, il suo tipo è Void
e il valore ottenuto non sarà nothing
.
Sequenza di Collatz
Il ciclo while
esegue il suo corpo finché dura la condizione. Ad esempio, il codice seguente calcola e stampa la sequenza Collatz da un numero dato:
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
Uso:
julia> collatz(10)
10
5
16
8
4
2
1... and 4, 2, 1, 4, 2, 1 and so on
È possibile scrivere qualsiasi ciclo in modo ricorsivo, e per cicli complessi while
volte la variante ricorsiva è più chiara. Tuttavia, in Julia, i loop presentano alcuni vantaggi distinti rispetto alla ricorsione:
- Julia non garantisce l'eliminazione delle chiamate tail, pertanto la ricorsione utilizza memoria aggiuntiva e può causare errori di overflow dello stack.
- Inoltre, per lo stesso motivo, un loop può avere un sovraccarico e correre più velocemente.
Esegui una volta prima di testare la condizione
A volte, si vuole eseguire un codice di inizializzazione una volta prima di testare una condizione. In certi altri linguaggi, questo tipo di loop ha una sintassi speciale do
- while
. Tuttavia, questa sintassi può essere sostituita con una normale istruzione while
loop e break
, quindi Julia non ha una sintassi specialistica do
- while
. Invece, si scrive:
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
Si noti che in alcune situazioni, tali cicli potrebbero essere più chiari con la ricorsione:
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
Ricerca per ampiezza
(Sebbene questo esempio sia scritto usando la sintassi introdotta nella versione v0.5, può funzionare anche con alcune modifiche su versioni precedenti).
Questa implementazione della ricerca in ampiezza (BFS) su un grafico rappresentato con elenchi di adiacenza utilizza i cicli while
e l'istruzione return
. Il compito che risolveremo è il seguente: abbiamo una sequenza di persone e una sequenza di amicizie (le amicizie sono reciproche). Vogliamo determinare il grado di connessione tra due persone. Cioè, se due persone sono amici, restituiremo 1
; se uno è amico di un amico dell'altro, restituiremo 2
, e così via.
Innanzitutto, supponiamo di avere già un elenco di adiacenze: un Dict
mappa T
to Array{T, 1}
, dove le chiavi sono persone ei valori sono tutti gli amici di quella persona. Qui possiamo rappresentare le persone con qualsiasi tipo T
scegliamo; in questo esempio, useremo Symbol
. Nell'algoritmo BFS, manteniamo una coda di persone da "visitare" e contrassegniamo la loro distanza dal nodo di origine.
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
Ora, scriveremo una funzione per costruire una lista di adiacenze data una sequenza di persone e una sequenza di tuple (person, person)
:
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
Ora possiamo definire la funzione originale:
degree(people, friendships, source, dest) =
degree(makeadjlist(people, friendships), source, dest)
Ora testiamo la nostra funzione su alcuni dati.
const people = [:jean, :javert, :cosette, :gavroche, :éponine, :marius]
const friendships = [
(:jean, :cosette),
(:jean, :marius),
(:cosette, :éponine),
(:cosette, :marius),
(:gavroche, :éponine)
]
Jean è collegato a se stesso in 0
passaggi:
julia> degree(people, friendships, :jean, :jean)
0
Jean e Cosette sono amici, e così hanno il grado 1
:
julia> degree(people, friendships, :jean, :cosette)
1
Jean e Gavroche sono collegati indirettamente attraverso Cosette e poi Marius, quindi la loro laurea è 3
:
julia> degree(people, friendships, :jean, :gavroche)
3
Javert e Marius non sono collegati attraverso alcuna catena, quindi viene generato un errore:
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