20 mars 2024
đ Julia
Syntaxe
Variables et types
Une variable est un espace mĂ©moire oĂč une valeur est stockĂ©e. Julia est un langage dynamique : il nâest donc pas nĂ©cessaire de dĂ©clarer le type dâune variable lors de sa crĂ©ation, il est dĂ©duit automatiquement par Julia au moment de son affectation.
Les variables sont crĂ©Ă©es en leur affectant une valeur Ă lâaide de lâopĂ©rateur =
.
julia> x = 1
1
julia> y = "Hello World!"
"Hello World!"
julia> x, y, z = 1, "A", [1, 2, 3]
(1, "A", [1, 2, 3])
julia> y
"A"
julia>
Si Julia est en mesure de déduire le type de la variable, il est aussi possible de la spécifier :
julia> a::Float64 = 3.0
3.0
julia> typeof(a)
Float64
Les types de donnĂ©es âsimplesâ (chaĂźnes, nombres, boolĂ©ens) sont immuables : leur contenu ne peut ĂȘtre modifiĂ© aprĂšs leur crĂ©ation. Si on affecte une nouvelle valeur, on crĂ©e en rĂ©alitĂ© une nouvelle instance de cette variable :
julia> x = 1
1
julia> x = x + 1 # une nouvelle variable est créée avec la valeur 2
2
Les types de donnĂ©es plus complexes comme les tableaux ou les dictionnaires sont mutables, câest-Ă -dire quâil est possible de modifier leur contenu :
julia> arr = [1, 2, 3]
3-element Vector{Int64}:
1
2
3
julia> arr[1] = 10
10
julia> arr
3-element Vector{Int64}:
10
2
3
Les variables dĂ©finies Ă lâextĂ©rieur de toute fonction ou bloc dispose dâune portĂ©e globale. Les variables dĂ©finies dans un bloc (boucle ou fonction par exemple) ont une portĂ©e locale.
Il est possible de définir des constantes avec le mot-clé const
. Un foie dĂ©finie, une constante ne peut plus ĂȘtre modifiĂ©e.
julia> const Ï = 3.14
3.14
Les types composites
Les types composites sont des collections champs nommĂ©s spĂ©cifiques, dont une instance peut ĂȘtre traitĂ©e comme une valeur unique. Ces objets sont utiles pour modĂ©liser des structures de donnĂ©es complexes, que lâon souhaite hiĂ©rarchiser ou lier, plutĂŽt que dâavoir plusieurs variables indĂ©pendantes par exemple.
julia> struct Person
name
age::Int # comme pour les variables il est possible de préciser le type de chaque champ
end
julia> sara = Person("Sara", 35)
Person("Sara", 35)
julia> sara.name
"Sara"
julia> fieldnames(Person) # pour connaitre les champs
(:name, :age)
Par défaut, une instance est immuable :
julia> sara.name = "Sarah"
ERROR: setfield!: immutable struct of type Person cannot be changed
Stacktrace:
[1] setproperty!(x::Person, f::Symbol, v::String)
@ Base ./Base.jl:41
[2] top-level scope
@ REPL[4]:1
Si lâon souhaite rendre un objet mutable, il faut le prĂ©ciser avec le mot-clĂ© mutable
.
julia> mutable struct Car
model::String
brand::String
end
julia> dino = Car("Dino", "Ferrari")
Car("Dino", "Ferrari")
julia> dino.brand = "FIAT"
"FIAT"
julia> dino
Car("Dino", "FIAT")
Une fois un type défini, il devient possible de lui associer des méthodes, ce qui permet de créer des fonctions spécifiques :
julia> struct Rectangle
width::Int
height::Int
end
julia> function area(r::Rectangle)
return r.width * r.height
end
area (generic function with 1 method)
julia> rect = Rectangle(10, 5)
Rectangle(10, 5)
julia> area(rect)
50
Pour aller plus loin voir aussi :
Opérateurs booléens et opérations mathématiques
Il existe 3 opérateurs booléens dans Julia
!
 : NOT||
 : OR&&
 : AND
Les opĂ©rateurs arithmĂ©tiques permettent dâeffectuer les opĂ©rations mathĂ©matiques de base sur les nombres :
+
 : addition-
 : soustraction^
 : puissance*
 : multiplication/
 : division\
 : division inverse (1\2 == 2/1 # true
)%
 : modulo
Avec Julia, lâordre dâĂ©valuation des opĂ©rateurs suit les conventions mathĂ©matiques (PEMDAS).
julia> 2*2+2^3-2/2
11.0
julia> 7%3
1
Quant aux Shorthand operators, ils combinent une opération et une affectation.
+=
 : addition-=
 : soustraction^=
 : puissance*=
 : multiplication/=
 : division\=
 : division inverse%=
 : modulo
julia> x = 1
1
julia> x += 2 # correspond Ă x = x + 2
3
Julia permet enfin de comparer des valeurs. Ces opérations retournent toujours un booléen.
julia>x, y, z = 1, 2, 3
(1, 2, 3)
Egalité :
==
 : égalité===
 : égalité stricte!=
 : inégalité
# égalité
julia> x == 1
true
julia> x == 1.0
true
julia> isequal(x, 1)
true
# égalité stricte
julia> x === 1
true
julia> x === 1.0
false
# inégalité
julia> x != y
true
# Not a number
julia> isnan(0/0)
true
julia> isnan('A')
ERROR: MethodError: no method matching isnan(::Char)
Plus grand que
>
 : plus grand>=
 : plus grand ou égal
Plus petit que
<
 : plus petit<=
 : plus petit ou égal
julia> x <= y <= z
true
Les fonctions
Une fonction associe la valeur dâun ou plusieurs arguments Ă une ou plusieurs valeurs de sortie. Une fonction Julia est dĂ©clarĂ©e ainsi :
julia> function my_function()
return println("Hello World!")
end
my_function (generic function with 1 method)
julia> my_function()
Hello World!
Il existe également une syntaxe compacte :
julia> greetings(name) = println("Greetings ", name)
greetings (generic function with 1 method)
julia> greetings("Space Captain")
Greetings Space Captain
Bien évidemment, il est possible de préciser les types :
julia> function multiply_numbers(x::Int64, y::Int64)
return x*y
end
multiply_numbers (generic function with 1 method)
julia> multiply_numbers(2, 4)
8
Les types permettent de dĂ©finir diffĂ©rentes mĂ©thodes, et donc dâinduire des comportements diffĂ©rents au regard de la nature des arguments :
julia> function multiply_numbers(x::Float64, y::Float64)
return x*y
end
multiply_numbers (generic function with 2 methods)
Une fonction peut Ă©galement retourner plusieurs valeurs. Dans ce cas, pour accĂ©der aux diffĂ©rentes valeurs, plusieurs options sâoffrent Ă nous, soit :
- associer une variable à chaque valeur ;
- associer une unique variable au résultat de la fonction et accéder aux valeurs avec
[]
,first()
etlast()
par exemple.
julia> function my_math(x, y)
add = x + y
sub = x - y
return add, sub
end
my_math (generic function with 1 method)
julia> my_math(3, 2)
(5, 1)
julia> output1, output2 = my_math(3, 2)
(5, 1)
julia> output2
1
julia> output = my_math(3, 2)
(5, 1)
julia> output[1]
5
julia> last(output)
1
Les fonctions Julia acceptent également des mots-clés comme arguments, ils sont séparés des arguments par un point-virgule (;
). Notons quâarguments et mots-clĂ©s peuvent disposer de valeurs par dĂ©faut :
julia> function logarithm(x; base=2.718281828459045)
return log(base, x)
end
logarithm (generic function with 1 method)
julia> logarithm(10)
2.302585092994046
julia> logarithm(10, base=2)
3.3219280948873626
julia>
Les fonctions anonymes
Pour des besoins plus spĂ©cifiques, il peut ĂȘtre nĂ©cessaire de crĂ©er rapidement des petites instructions, par exemple pour filtrer des rĂ©sultats. On utilise alors gĂ©nĂ©ralement des fonctions anonymes. Ces fonctions sâutilisent alors comme arguments dâautres fonctions, comme map()
par exemple. Elles reposent sur lâopĂ©rateur ->
. Ă la gauche de cet opĂ©rateur, on dĂ©finit les paramĂštres, et Ă droite on dĂ©finit les opĂ©rations que lâon souhaite effectuer.
julia> arr = [1, 2, 3]
3-element Vector{Int64}:
1
2
3
julia> map(x -> x + 1, arr) # on utilise la fonction map() pour associer la fonction au tableau
3-element Vector{Int64}:
2
3
4
Plusieurs arguments peuvent ĂȘtre passĂ©s,, ils faut alors les placer entre parenthĂšses : (x, y, z) -> x + y + z
.
Les fonctions avec un opérateur bang !
LâopĂ©rateur bang !
est une convention Julia pour indiquer quâune fonction modifie un ou plusieurs de ses arguments (side effect).
ChaĂźnage
LâopĂ©rateur |>
 permet de chaßner des opérations :
julia> function add_two(i)
return i + 2
end
add_two (generic function with 1 method)
julia> function div_by_two(i)
return i / 2
end
div_by_two (generic function with 1 method)
julia> 1 |> add_two |> div_by_two
1.5
Les conditions
Julia utilise les mots-clés if
, elseif
et else
pour afin dâĂ©valuer des expressions et exĂ©cuter une portion de code particuliĂšre.
julia> a, b = 1, 2
(1, 2)
julia> if a > b
"a est plus grand que b"
elseif a == b
"a est Ă©gal Ă b"
else
"a est plus petit que b"
end
"a est plus petit que b"
Il est aussi possible dâutiliser une syntaxe simplifiĂ©e pour les Ă©valuations simples avec lâopĂ©rateur ternaire ?
julia> x, y = 1, 2
(1, 2)
julia> x == y ? "x = y " : "x â y"
"x â y"
julia> x < y ? "x < y" : "x > y"
"x < y"
Les boucles
For
Les boucles for
permettent dâitĂ©rer des opĂ©rations pour chaque Ă©lĂ©ment dâune sĂ©quence.
julia> for i in 1:3
println(i)
end
1
2
3
While
La boucle while
est un peu Ă mi-chemin entre les conditions if
et la boucle for
. Tant quâune condition nâest pas remplie, la boucle while
continue ses itérations.
julia> x = 0
0
julia> while x < 6
println(x) # on imprime x
global x += 2 # on rajoute + 2 Ă la variable globale x
end
0
2
4
Les types simples
Les chaĂźnes de caractĂšres
Les caractĂšres sont placĂ©s entre guillemets simples et il est possible de coder un caractĂšre sous la forme dâun entier
julia> c = 'a'
'a': ASCII/Unicode U+0061 (category Ll: Letter, lowercase)
julia> c = Int(c)
97
julia> Char(97)
'a': ASCII/Unicode U+0061 (category Ll: Letter, lowercase)
Il est donc possible dâeffectuer des comparaisons ou des opĂ©rations arithmĂ©tiques.
julia> 'A' < 'a'
true
julia> 'A' + 1
'B': ASCII/Unicode U+0042 (category Lu: Letter, uppercase)
Les chaĂźnes de caractĂšres sont placĂ©es entre guillemets doubles, ou triple sâil y a des guillemets doubles dedans.
julia> str = "Hello World!"
"Hello World!"
julia> str = """Victore Hugo a prononcé la phrase "Ce gouvernement, je le caractérise d'un mot : la police partout, la justice nulle part" le 17 juillet 1851."""
"Victore Hugo a prononcé la phrase "Ce gouvernement, je le caractérise d'un mot : la police partout, la justice nulle part" le 17 juillet 1851."
=#
julia> typeof(str)
String
Opérations sur les Strings
Il est possible dâitĂ©rer sur une chaine de caractĂšres.
julia> for c in "Hello"
println(c)
end
H
e
l
l
o
De la mĂȘme maniĂšre, il est possible de mesurer la longueur dâune chaĂźne avec les fonctions length()
et lastindex()
.
julia> str = "BodÞ est une ville norvégienne située dans le comté de Nordland"
"BodÞ est une ville norvégienne située dans le comté de Nordland"
julia> length(str)
63
Attention cependant Ă lâencodage des caractĂšres, length()
et lastindex()
ne retournent pas toujours le mĂȘme rĂ©sultat.
julia> lastindex(str)
67
La concatĂ©nation sâeffectue avec lâopĂ©rateur *
ou la fonction join()
, et lâinterpolation avec $
julia> "Hello"*" "*"World"*"!"
"Hello World!"
julia> jours = ["lundi", "mardi", "mercredi", "jeudi", "vendredi", "samedi", "dimanche"]
7-element Vector{String}:
"lundi"
"mardi"
"mercredi"
"jeudi"
"vendredi"
"samedi"
"dimanche"
julia> join(jours, ", ", " et ")
"lundi, mardi, mercredi, jeudi, vendredi, samedi et dimanche"
julia> surname, forename = "Hugo", "Victor"
("Hugo", "Victor")
julia> fullname = "$forename $surname"
"Victor Hugo"
Les occurrences de caractĂšres ou de chaĂźne de caractĂšres peuvent ĂȘtre recherchĂ©es.
julia> findfirst('l', "Hello World")
3
julia> findlast('l', "Hello World")
10
julia> findprev('l', "Hello World", 5)
4
julia> findnext('l', "Hello World", 5)
10
julia> findall('l', "Hello World")
3-element Vector{Int64}:
3
4
10
julia> occursin("world", "Hello world!")
true
julia> occursin("Goodbye", "Hello world!")
false
Julia prend aussi en charge les expressions réguliÚres (RegEx)
julia> str = "Hello World!"
"Hello World!"
julia> r = r"l"
r"l"
julia> typeof(r)
Regex
julia> occursin(r, str)
true
julia> match(r, str)
RegexMatch("l")
julia> m = match(r"[0-9]", str) # si aucun match retour "nothing"
julia> if m === nothing
return "no match"
else
return "match"
end
"no match"
julia> m = match(r"(ll).*(l)", str)
RegexMatch("llo Worl", 1="ll", 2="l")
julia> m.match
"llo Worl"
julia> m.captures
2-element Vector{Union{Nothing, SubString{String}}}:
"ll"
"l"
julia> m = match(r"(?d+):(?d+)","12:45")
RegexMatch("12:45", hour="12", minute="45")
julia> m[:minute]
"45"
julia> m[2]
"45"
julia> m = eachmatch(r, str)
Base.RegexMatchIterator(r"l", "Hello World!", false)
julia> collect(m)
3-element Vector{RegexMatch}:
RegexMatch("l")
RegexMatch("l")
RegexMatch("l")
julia> [m.match for m = eachmatch(r, str)]
3-element Vector{SubString{String}}:
"l"
"l"
"l"
Enfin, toutes les opérations classiques sur les substrings sont possibles.
- pour les extraire
julia> str = "Hello World!"
"Hello World!"
julia> str[2]
'e': ASCII/Unicode U+0065 (category Ll: Letter, lowercase)
julia> str[1:5]
"Hello"
julia> str[begin:end-6]
"Hello "
julia> str[1]
'H': ASCII/Unicode U+0048 (category Lu: Letter, uppercase)
julia> str[1:1]
"H"
julia> SubString(str, 1, 5)
"Hello"
- pour savoir si une chaĂźne contient (
contains()
), commence (startswith()
) ou se termine (endswith()
) par telle expression.
julia> str = "Hello World"
"Hello World"
julia> contains(str, "Hello")
true
- pour remplacer un segment
julia> replace(str, "Hello" => "Goodbye")
"Goodbye World!"
- pour les tokeniser (
split()
)
julia> split(str, " ")
2-element Vector{SubString{String}}:
"Goodbye"
"World"
pour les transformer
lowercase()
,uppercase()
,titlecase()
,lowercasefirst()
, etc.ou encore pour les convertir
julia> n = 123
123
julia> string(n) # de nombre vers string
"123"
julia> parse(Int64, "123") # ou de string vers nombre
123
Range
Le type UnitRange
correspond Ă un intervalle.
julia> r = 1:10
1:10
julia> typeof(r)
UnitRange{Int64}
Pour récupérer les valeurs de cet intervalle on peut utiliser une boucle, ou la fonction collect()
julia> collect(r)
10-element Vector{Int64}:
1
2
3
4
5
6
7
8
9
10
Il est aussi possible de modifier le pas dâun intervalle avec la syntaxe start:step:stop
.
ulia> r = 1:0.5:3
1.0:0.5:3.0
julia> collect(r)
5-element Vector{Float64}:
1.0
1.5
2.0
2.5
3.0
Symbols
@todo
Data structures
Paires et dictionnaires
Une paire est constituée de deux objets : une clé sa une valeur.
julia> p = "key" => "value" # ou symbole pour la clé :key => "value"
"key" => "value"
julia> p[1]
"key"
julia> p.first
"key"
Un dictionnaire est constituĂ© dâune ou plusieurs paires, ils sont trĂšs commodes pour retrouver la valeur attachĂ©e Ă une clĂ©.
Ils peuvent ĂȘtre dĂ©clarĂ© soit Ă partir dâun vecteur tuple
s soit directement Ă partir de paires
julia> Dict( [("A", 1), ("B", 2)] )
Dict{String, Int64} with 2 entries:
"B" => 2
"A" => 1
julia> Dict( "A" => 1, "B" => 2)
Dict{String, Int64} with 2 entries:
"B" => 2
"A" => 1
# il est possible de typer les clés ou les valeurs
julia> d = Dict{String, Integer}( "A" => 1, "B" => 2, "C" => "Hello World")
ERROR: MethodError: Cannot `convert` an object of type String to an object of type Integer
Opérations sur les clés/valeurs
- récupérer les clés ou les valeurs avec
keys()
etvalues()
, ou tester la prĂ©sence dâune clĂ© avechaskey()
julia> d = Dict{Symbol, Any}(
:hello => "world",
:adios => "Amigos"
)
Dict{Symbol, Any} with 2 entries:
:hello => "world"
:adios => "Amigos"
julia> keys(d)
KeySet for a Dict{Symbol, Any} with 2 entries. Keys:
:hello
:adios
julia> values(d)
ValueIterator for a Dict{Symbol, Any} with 2 entries. Values:
"world"
"Amigos"
julia> haskey(d, "salut")
false
- créer un tableau à partir de la liste des clés / valeurs avec
collect()
julia> collect(values(d))
2-element Vector{Any}:
"world"
"Amigos"
- rĂ©cupĂ©rer la valeur dâune clĂ© avec
get
ou en appelant lakey
dans lâopĂ©rateur[]
.
julia> get(d, :hello, "pas de clé :hello")
"world"
julia> get(d, "hello", "pas de clé 'hello'") # cherche une clé de type String
"pas de clé 'hello'"
julia> d[:hello]
"world"
- amender un dictionnaire avec
delete!()
oupop!()
julia> delete!(d, :adios)
Dict{Symbol, Any} with 1 entry:
:hello => "world"
# si la clé n'existe pas, le dictionnaire n'est pas modifié.
julia> pop!(d, :hello)
"world"
# pop!() retourne une erreur si la clé n'est pas trouvée...
julia> pop!(d, :hello)
ERROR: KeyError: key :hello not found
# ⊠ou une valeur par défaut si elle est précisée
julia> pop!(d, :hola, 0)
0
- fusionner des dictionnaires avec
merge()
(voir aussimerge!()
etmergewith()
. )
julia> a = Dict("foo" => 0.0, "bar" => 42.0)
Dict{String, Float64} with 2 entries:
"bar" => 42.0
"foo" => 0.0
julia> b = Dict("baz" => 17, "bar" => 4711)
Dict{String, Int64} with 2 entries:
"bar" => 4711
"baz" => 17
julia> merge(a, b)
Dict{String, Float64} with 3 entries:
"bar" => 4711.0 # la valeur du second remplace celle du premier
"baz" => 17.0
"foo" => 0.0
Avec merge!()
,il faut parfois ajouter les types pour résoudre les problÚmes de fusion (merge()
(sans!) ne semble pas impactée).
julia> d = Dict(
:title => "myTitle",
:date => "2024-01-01"
)
julia> c = Dict(
:files => [
"file1.text",
"file2.text"
]
)
julia> merge!(d, c)
ERROR: MethodError: Cannot `convert` an object of type Vector{String} to an object of type String
julia> d = Dict{Symbol, Any}(
:title => "myTitle",
:date => "2024-01-01"
)
Les tableaux
Un tableau, ou array, est une sĂ©quence dâobjets ou de valeurs. GĂ©nĂ©ralement un array contient un type de donnĂ©es, mais ce nâest pas une obligation.
julia> a = [1, 2, 3]
3-element Vector{Int64}:
1
2
3
julia> b = [1, 'a', ['α', 'ÎČ']]
3-element Vector{Any}:
1
'a': ASCII/Unicode U+0061 (category Ll: Letter, lowercase)
['α', 'ÎČ']
julia> [1 2 # une matrice
3 4]
2Ă2 Matrix{Int64}:
1 2
3 4
Il existe deux types dâarray :
- les vecteurs,
Vector{T}
, (une dimension)Â ; - les matrices,
Matrix{T}
(deux dimensions).
Il existe plusieurs mĂ©thodes pour crĂ©er des tableaux. La premiĂšre mĂ©thode est dâutiliser les constructeurs par dĂ©faut Vector{T}(undef, n)
(construit un Vector{T}
non initialisé de longueur n
.) ou Matrix{T}(undef, m, n)
(matrice non initialisée de taille m
x n
)
julia> a = Vector{Float64}(undef, 3)
3-element Vector{Float64}:
2.03e-322
6.5e-322
2.2062283473e-314
julia> a = Matrix{Float64}(undef, 3, 2)
3Ă2 Matrix{Float64}:
2.20472e-314 2.20472e-314
2.20472e-314 2.20472e-314
2.20472e-314 2.20472e-314
Julia dispose Ă©galement dâalias syntaxiques pour les Ă©lĂ©ments les plus courants dans la construction de tableaux :
julia> v = zeros(5) # initialise avec des O on peut aussi passer un type zeros(Float64, 5)
5-element Vector{Float64}:
0.0
0.0
0.0
0.0
0.0
julia> m = ones(5, 3) # initialise avec des 1
5Ă3 Matrix{Float64}:
1.0 1.0 1.0
1.0 1.0 1.0
1.0 1.0 1.0
1.0 1.0 1.0
1.0 1.0 1.0
Il est aussi possible dâinstancier un array vide puis de la remplir avec fill!()
.
julia> m = Matrix{Float64}(undef, 2, 2)
2Ă2 Matrix{Float64}:
1.6e-322 2.20881e-314
2.351e-314 1.0e-323
julia> fill!(m, Ï)
2Ă2 Matrix{Float64}:
3.14159 3.14159
3.14159 3.14159
Ou simplement en utilisant des crochets []
julia> [1, 2, 3]
3-element Vector{Int64}:
1
2
3
julia> [x*2 for x in 1:4]
4-element Vector{Int64}:
2
4
6
8
julia> [zeros(3) ones(3)]
3Ă2 Matrix{Float64}:
0.0 1.0
0.0 1.0
0.0 1.0
La concatĂ©nation peut aussi ĂȘtre utilisĂ©e pour crĂ©er un nouvel array (cat()
).
julia> cat(ones(3), ones(3), dims=2) # voir aussi hcat() (cat(âŠ; dims=2)) et vcat() (cat(âŠ; dims=1))
3Ă2 Matrix{Float64}:
1.0 1.0
1.0 1.0
1.0 1.0
julia> arrA = [1, 2, 3]
julia> arrB = [4, 5, 6]
julia> append!(arrA, arrB) # concat arrB Ă la suite de arrA
6-element Vector{Int64}:
1
2
3
4
5
6
Une fois la tableaux établit, il est possible de le parcourir. Mais préalablement, il est souvent nécessaire de connaßtre les caractéristiques du tableau : taille (size()
), longueur (length()
), dimensions (ndims()
), type des éléments (eltype()
)
julia> v = [1, 2, 3]
3-element Vector{Int64}:
1
2
3
julia> m = [1 2 3
4 5 6]
2Ă3 Matrix{Int64}:
1 2 3
4 5 6
julia> size(m)
(2, 3)
julia> ndims(v)
1
Les valeurs dans un tableau sont indexées par des des entiers, il est donc trÚs facile de récupérer une valeur ou un segment.
julia> v[2]
2
julia> v[2:end]
2-element Vector{Int64}:
2
3
julia> m
2Ă3 Matrix{Int64}:
1 2 3
4 5 6
julia> m[2, 2]
5
julia> m[2, :]
3-element Vector{Int64}:
4
5
6
julia> m[:, 1]
2-element Vector{Int64}:
1
4
Les tableaux sont mutables, il est donc possible de réassigner une valeur ou un segment trÚs simplement en utilisant le signe =
, mais aussi dâajouter des valeurs (push!()
, pushfirst!()
), dâen supprimer (pop!()
, popfirst!()
et deleteat!()
), de le trier (sort!()
).
julia> m
2Ă3 Matrix{Int64}:
1 2 3
4 5 6
julia> m[2, 2] = 50
50
julia> m
2Ă3 Matrix{Int64}:
1 2 3
4 50 6
julia> arr = Integer[1, 2, 3]
3-element Vector{Integer}:
1
2
3
julia> pop!(arr) # suppression d'un élément en fin de tableau
3
julia> popfirst!(arr) # suppression d'un élément en debut tableau
1
julia> arr
1-element Vector{Integer}:
2
julia> pushfirst!(arr, 1)
2-element Vector{Integer}:
1
2
julia> push!(arr, 3)
3-element Vector{Integer}:
1
2
3
julia> deleteat!(arr, 2)
2-element Vector{Integer}:
1
3
julia> sort!(['c', 'b', 'a'])
3-element Vector{Char}:
'a': ASCII/Unicode U+0061 (category Ll: Letter, lowercase)
'b': ASCII/Unicode U+0062 (category Ll: Letter, lowercase)
'c': ASCII/Unicode U+0063 (category Ll: Letter, lowercase)
Il est Ă©galement possible de modifier la forme dâun tableau, comme par exemple passer dâun vecteur Ă un matrice, Ă lâaide de la fonction reshape()
julia> v = [1, 2, 3, 4]
4-element Vector{Int64}:
1
2
3
4
julia> v2m = reshape(v, (2, 2)) # création d'une matrice 2x2
2Ă2 Matrix{Int64}:
1 3
2 4
julia> m = reshape(v2m, (4,)) # création d'un vecteur à partir d'une matrice.
4-element Vector{Int64}:
1
2
3
4
Des fonctions peuvent ĂȘtre appliquĂ©es Ă chaque Ă©lĂ©ment dâun array. On utilise gĂ©nĂ©ralement lâopĂ©rateur dot
(broadcasting).
julia> [1, 2, 3] .+ [4, 5, 6] # [1+4, 2+5, 3+6]
3-element Vector{Int64}:
5
7
9
julia> [1, 2, 3] .-1
3-element Vector{Int64}:
0
1
2
julia> extentions = ["jpg", "JPG", "jpeg", "png", "PNG", "tif", "tiff"]
julia> file = "picture.jpg"
julia> endswith.(file, extentions) # retourne un vecteur de booléens
7-element BitVector:
1
0
0
0
0
0
0
# voir d'autres exemple dans les opérateurs de collection (in)
Attention a la vectorisation avec lâopĂ©rateur in
. Si les deux arguments sont des vecteurs de mĂȘme longueur (retourne un erreur si les dimension ne correspondent pas), in.(items, collection)
retourne un vecteur indiquant si chaque valeur de items
est dans la valeur Ă la position correspondante dans collection
.
julia> in.([1,2], [2,3])
2-element BitVector:
0
0
Pour obtenir un vecteur indiquant si chaque item est dans la collection, il faut envelopper la collection dans un tuple
ou un Ref()
julia> in.([1,2], ([2,3],)) # ne pas oublier la virgule
2-element BitVector:
0
1
# ou in.([1,2], Ref([2,3]))
Produit scalaire
julia> a = [1, 2, 3]
julia> b = [2, 3, 4]
julia> sum(a .* b) # (1*2 + 2*3 + 3*4)
20
Une autre possibilitĂ© est dâutiliser la fonction map()
.
julia> map(x -> x+1, [1, 2, 3])
3-element Vector{Int64}:
2
3
4
De nombreuses autres opérations sont applicables aux tableaux : jointure, appartenance, contient, sous-ensemble, etc.
julia> arr = [1, 2, 3]
julia> join(arr, ",")
"1,2,3"
Opérateurs :
in
|â
 : appartientâ
 : nâappartient pasissubset
 : sous-ensemble
julia> a = 1:5
julia> 3 in a # autres notations : in(3, 1:5) ou 3 â 1:5
true
Attention avec la valeur missingâŠ
julia> 1 in [1, missing]
true
julia> missing in [1, missing]
missing
julia> issubset([1, 2], [1, 2, 3])
true
Tuples
Un tuple
est assez proche dâun tableau, il correspond Ă une sĂ©quence de valeurs indexĂ©es par des entiers. Les valeurs sont sĂ©parĂ©es par une virgule et chacune peut disposer de son propre type. On les place gĂ©nĂ©ralement entre parenthĂšses mais ces derniĂšres ne sont pas obligatoires. Ils se distinguent des tableaux par leur caractĂšre immuable.
julia> t = 1, 2, 3
(1, 2, 3)
julia> t = (1, 2, 3)
(1, 2, 3)
julia> t = (1,)
(1,)
julia> typeof(t)
Tuple{Int64}
julia> tuple(1, 2) # on peut Ă©galement utiliser la fonction tuple()
(1, 2)
julia> t[1] # comme pour les tableaux, les valeurs sont indexées.
1
Les tuples sont trĂšs utilisĂ©s pour lâaffectation (ou rĂ©affectation) de variables.
julia> a, b = 1, 2
(1, 2)
julia> str = "Hello World"
"Hello World"
julia> (a, b) = split(str, " ")
2-element Vector{SubString{String}}:
"Hello"
"World"
Certaines fonctions peuvent prendre un nombre variable dâarguments, reconnaissables par les ...
qui suivent le nom du paramÚtre. Dans ce cas, les différents arguments sont agrégés dans un tuple.
julia> function add(args...)
sum(args)
end
add (generic function with 1 method)
julia> add(1, 2, 3, 4, 5)
15
On peut avoir recours au tuples lorsque lâon souhaite passer plusieurs arguments dans une fonction anonyme.
julia> map((x, y, z) -> x*y^z, 4, 9, 2)
324
Un nom peut ĂȘtre associĂ© a chaque valeur dâun tuple.
julia> (a='a', b='c', c='c')
(a = 'a', b = 'c', c = 'c')
Une syntaxe existe Ă©galement pour crĂ©er un tuple nommĂ© Ă partir de variables prĂ©existantes. Elle reprend le principe des arguments mots-clĂ©s avec les fonctions et lâemploi dâun point-virgule ;
.
julia> a, b = 'a', 'b'
('a', 'b')
julia> t = (; a, b)
(a = 'a', b = 'b')
Voir aussi les utilisations de collect()
et zip()
avec les tuples.
DataFrames
Il existe de nombreuses méthodes pour créer un DataFrames, à partir de vecteurs, de paires, de vecteurs de paires, de dictionnaires, avec des tuples de vecteurs nommés, colonne par colonne, ligne à ligne, etc.
julia> using DataFrames
julia> DataFrame(
a=1:4,
b=["Yoda", "Han Solo", "Luke", "Dark Vador"]
)
4Ă2 DataFrame
Row â a b
â Int64 String
ââââââŒâââââââââââââââââââ
1 â 1 Yoda
2 â 2 Han Solo
3 â 3 Luke
4 â 4 Dark Vador
# avec des paires
julia> DataFrame("a" => 1:2, "b" => ["Yoda", "Han Solo"])
# avec un vecteur de paires
julia> DataFrame(["a" => 1:2, "b" => ["Yoda", "Han Solo"]])
# avec un dictionnaire
julia> DataFrame(Dict(
"a" => 1:2,
"b" => ["Yoda", "Han Solo"]
))
# un tuple de vecteurs identifiés...
julia> DataFrame((a=[1, 2], b=["Yoda", "Han Solo"]))
# ... ou un vecteur de tuples
julia> DataFrame([(a=1, b="Yoda"), (a=2, b="Han Solo")])
# construction colonne par colonne
julia> df = DataFrame()
julia> df.a = 1:2 # ajout de la colonne a
julia> df[!, :b] = ["Yoda", "Han Solo"] #ajout de la colonne b (autre syntaxe)
# construction ligne Ă ligne
julia> df = DataFrame(a=Int[], b=String[])
julia> push!(df, (1, "Yoda"))
julia> push!(df, (2, "Han Solo"))
# Il est possible d'utiliser pushfirst!() pour ajouter une ligne au début
# insert!() pour ajouter une ligne à un index donné
# append!() ou prepend!() pour ajouter des tables entiĂšres
Et mĂȘme Ă partir de donnĂ©es tabulaires
#data.csv
a,b
1,"Yoda"
2,"Han Solo"
julia> using CSV
julia> df = DataFrame(CSV.File("data.csv"))
2Ă2 DataFrame
Row â a b
â Int64 String
ââââââŒâââââââââââââââââ
1 â 1 Yoda
2 â 2 Han Solo
Les noms des colonnes peuvent ĂȘtre rĂ©cupĂ©rĂ©s sous la forme dâun vecteur avec la fonction names()
julia> names(df)
2-element Vector{String}:
"a"
"b"
julia> propertynames(df) # retourne les noms de colonne sous forme de symboles
2-element Vector{Symbol}:
:a
:b
Cette mĂȘme fonction permet de faire des recherches dans le noms de colonnes.
julia> names(df, r"a") # liste les colonnes avec RegEx
julia> names(df, Not(:b)) # tous les noms de colonnes sauf :b
julia> names(df, Int) # liste les colonnes en fonction du type de données
On peut rĂ©cupĂ©rer un vecteur des valeurs dâune colonne de diffĂ©rentes maniĂšres
julia> df.b
julia> df."b"
julia> df[!, :b]
julia> df[!, "b"]
julia> df[:, :b]
julia> df[:, "b"]
2-element Vector{String}:
"Yoda"
"Han Solo"
Il existe cependant une différente entre df[!, :b]
et df[:, :b]
 : le bang operator !
indique quâune copie nâest pas rĂ©alisĂ©e. Si on change un Ă©lĂ©ment du vecteur alors il sera propagĂ© au Dataframe.
Columns can be directly (i.e. without copying) accessed via df.col or df[!, :col]. [âŠ] Since df[!, :col] does not make a copy, changing the elements of the column vector returned by this syntax will affect the values stored in the original df. To get a copy of the column use df[:, :col]: changing the vector returned by this syntax does not change df.
julia> df = DataFrame(["a" => 1:2, "b" => ["Yoda", "Han Solo"]])
julia> v = df[:, :b] # pas de bang, la valeur ne sera pas modifiée
2-element Vector{String}:
"Yoda"
"Han Solo"
julia> v[2] = "Dark Vador"
"Dark Vador"
julia> df
2Ă2 DataFrame
Row â a b
â Int64 String
ââââââŒâââââââââââââââââ
1 â 1 Yoda
2 â 2 Han Solo
julia> v = df[!, :b] # bang opérateur
julia> v[2] = "Dark Vador"
julia> df # utilisation de bang, la valeur est modifiée.
2Ă2 DataFrame
Row â a b
â Int64 String
ââââââŒâââââââââââââââââââ
1 â 1 Yoda
2 â 2 Dark Vador
Voir la documentation pour travailler avec les subsets et pour les nombreuses options de tri.
Pour récupérer une ligne ou un groupe de lignes et/ou des colonnes spécifiques, on utilise la notation suivante :
julia> names = ["Yoda", "Dark Vador", "Luke Skywalker", "Mace Windu"]
4-element Vector{String}:
"Yoda"
"Dark Vador"
"Luke Skywalker"
"Mace Windu"
julia> side = ["light", "dark", "light", "light"]
4-element Vector{String}:
"light"
"dark"
"light"
"light"
julia> df = DataFrame(; name=names, side=side)
4Ă2 DataFrame
Row â name side
â String String
ââââââŒââââââââââââââââââââââââ
1 â Yoda light
2 â Dark Vador dark
3 â Luke Skywalker light
4 â Mace Windu light
julia> df[1:2, :]
2Ă2 DataFrame
Row â name side
â String String
ââââââŒââââââââââââââââââââ
1 â Yoda light
2 â Dark Vador dark
julia> df[3, :]
DataFrameRow
Row â name side
â String String
ââââââŒââââââââââââââââââââââââ
3 â Luke Skywalker light
julia> df[[1, 3], :side] # lignes 1 et 3 uniquement la colonne side
2-element Vector{String}:
"light"
"light"
julia> df[[1, 3], [:side, :name]] # uniquement lignes 1 et 3 et colonne side et name
2Ă2 DataFrame
Row â side name
â String String
ââââââŒââââââââââââââââââââââââ
1 â light Yoda
2 â light Luke Skywalker
On peut Ă©galement filtrer les rĂ©sultats en fonction de la valeur dâune ou de plusieurs cellules :
julia> df[df.side .== "light", :]
3Ă2 DataFrame
Row â name side
â String String
ââââââŒââââââââââââââââââââââââ
1 â Yoda light
2 â Luke Skywalker light
3 â Mace Windu light
julia> df[(df.name .== "Yoda") .|| (df.side .== "dark"), :]
2Ă2 DataFrame
Row â name side
â String String
ââââââŒââââââââââââââââââââ
1 â Yoda light
2 â Dark Vador dark
La fonction subset()
peut aussi ĂȘtre utilisĂ©e :
julia> subset(df, :name => n -> n .== "Yoda")
1Ă2 DataFrame
Row â name side
â String String
ââââââŒââââââââââââââââ
1 â Yoda light
julia> subset(df, :name => n -> n .== "Yoda", :side => s -> s .== "dark")
0Ă2 DataFrame
Row â name side
â String String
ââââââŽââââââââââââââââ
# retourne un df vide car aucune ligne ne répond au x deux conditions
Des colonnes peuvent ĂȘtre ajoutĂ©es Ă un DataFrame existant :
julia> df.midichlorians = [17000, 27000, 14000, 12000]
4-element Vector{Int64}:
17000
27000
14000
12000
julia> df.lighsaber = missings(String, nrow(df))
4-element Vector{Union{Missing, String}}:
missing
missing
missing
missing
julia> df
4Ă4 DataFrame
Row â name side midichlorians lighsaber
â String String Int64 String?
ââââââŒââââââââââââââââââââââââââââââââââââââââââââââââââ
1 â Yoda light 17000 missing
2 â Dark Vador dark 27000 missing
3 â Luke Skywalker light 14000 missing
4 â Mace Windu light 12000 missing
Copie
a = [[1,2,3], [4,5,6]]
b = copy(a)
c = deepcopy(a) #recursif
a[1][1] = 11
a
#=
2-element Vector{Vector{Int64}}:
[11, 2, 3]
[4, 5, 6]
=#
b
#=
2-element Vector{Vector{Int64}}:
[11, 2, 3]
[4, 5, 6]
=#
c
#=
2-element Vector{Vector{Int64}}:
[1, 2, 3]
[4, 5, 6]
=#
autre
contains()
et occursin()
sont les mĂȘmes fonctions, mais les arguments sont inversĂ©s. contains()
est alignée avec startswith()
et endswith()
.
contains("Hello World!", "Hello") # true
occursin("Hello", "Hello World!") # true
issubset([1, 2], [1, 2, 3]) # true
issubset("Hello", "Hello World!") # true
Les symboles LaTeX
Commentaires
v = 12 # un commentaire de fin de ligne
#=
Un bloc de commentaire
qui peut s'etendre
sur plusieurs
lignes
=#
Chainage
x = y = z = 1
#=
x = 1
y = 1
z = 1
=#
0<x<2 # true
Symboles LaTeX
Il est possible dâutiliser les symboles LaTeX directement dans Julia.
# \beta [+ tabulation]
ÎČ = 10