Julia Language
в то время как циклы
Поиск…
Синтаксис
- в то время как cond; тело; конец
- перерыв
- Продолжить
замечания
В while
цикл не имеет значения; хотя его можно использовать в позиции выражения, его тип - Void
и полученное значение будет nothing
.
Последовательность Collatz
В while
цикл выполняется его тело, пока имеет место условие. Например, следующий код вычисляет и печатает последовательность Collatz с заданного числа:
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
Использование:
julia> collatz(10)
10
5
16
8
4
2
1... and 4, 2, 1, 4, 2, 1 and so on
Можно написать любой цикл рекурсивно, так и для комплекса , while
петли, иногда рекурсивный вариант более ясно. Однако в Julia циклы имеют определенные преимущества перед рекурсией:
- Julia не гарантирует устранения хвостового вызова, поэтому рекурсия использует дополнительную память и может вызвать ошибки переполнения стека.
- И далее, по той же причине, цикл может уменьшиться накладные расходы и работать быстрее.
Запуск один раз перед тестированием
Иногда перед запуском какого-либо условия требуется запустить некоторый код инициализации. В некоторых других языках этот вид цикла имеет специальный синтаксис do
while
. Тем не менее, этот синтаксис может быть заменен постоянным во while
цикла и break
заявление, поэтому Джулия не специализировалась do
- в while
синтаксис. Вместо этого вы пишете:
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
Обратите внимание, что в некоторых ситуациях такие циклы могут быть более ясными с рекурсией:
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
Поиск по ширине
(Хотя этот пример написан с использованием синтаксиса, представленного в версии v0.5, он может работать и с небольшими изменениями в старых версиях.)
Эта реализация поиска по ширине (BFS) на графике, представленном списками смежности, использует циклы while
и оператор return
. Задача, которую мы решаем, заключается в следующем: у нас есть последовательность людей, и последовательность дружеских отношений (дружба взаимна). Мы хотим определить степень связи между двумя людьми. То есть, если два человека являются друзьями, мы вернем 1
; если кто-то друг друга другого, мы вернем 2
и т. д.
Сначала предположим, что у нас уже есть список смежности: Dict
отображающий T
в Array{T, 1}
, где ключи - это люди, а значения - все друзья этого человека. Здесь мы можем представлять людей с любым типом T
мы выбираем; в этом примере мы будем использовать Symbol
. В алгоритме BFS мы сохраняем очередь людей для «посещения» и отмечаем их расстояние от узла происхождения.
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
Теперь мы напишем функцию для построения списка смежности с учетом последовательности людей и последовательности (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
Теперь мы можем определить исходную функцию:
degree(people, friendships, source, dest) =
degree(makeadjlist(people, friendships), source, dest)
Теперь давайте проверим нашу функцию на некоторых данных.
const people = [:jean, :javert, :cosette, :gavroche, :éponine, :marius]
const friendships = [
(:jean, :cosette),
(:jean, :marius),
(:cosette, :éponine),
(:cosette, :marius),
(:gavroche, :éponine)
]
Жан связан с собой в 0
шагах:
julia> degree(people, friendships, :jean, :jean)
0
Джин и Козетт - друзья, и у них есть степень 1
:
julia> degree(people, friendships, :jean, :cosette)
1
Жан и Гаврох связаны косвенно через Косет, а затем Мариус, поэтому их степень составляет 3
:
julia> degree(people, friendships, :jean, :gavroche)
3
Javert и Marius не связаны ни с одной цепью, поэтому возникает ошибка:
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