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)
Float64Les 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 
2Les 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
  3Les 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.14Les 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]:1Si 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)
50Pour 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
1Quant 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
3Julia 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 CaptainBien é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)
8Les 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)
1Les 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
 4Plusieurs 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.5Les 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
3While
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
4Les 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)
StringOpé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
oDe 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)
63Attention cependant Ă  lâencodage des caractĂšres, length() et lastindex() ne retournent pas toujours le mĂȘme rĂ©sultat.
julia> lastindex(str)
67La 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!")
falseJulia 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
123Range
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
 10Il 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.0Symbols
@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 tuples  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 IntegerOpé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 getou en appelant lakeydans 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.0Avec 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  4Il 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-314Julia 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.0Il 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.14159Ou 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.0La 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
 6Une 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)
1Les 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
 4Les 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
 4Des 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
 0Pour 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
 4De 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 pas
- issubset : sous-ensemble
julia> a = 1:5
julia> 3 in a # autres notations : in(3, 1:5) ou 3 â 1:5
trueAttention avec la valeur missingâŠ
julia> 1 in [1, missing]
true
julia> missing in [1, missing]
missingjulia> issubset([1, 2], [1, 2, 3])
trueTuples
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.
1Les 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)
15On 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)
324Un 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 SoloLes 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
 :bCette 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Ă©esOn 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 VadorVoir 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 SkywalkerOn 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  darkLa 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 conditionsDes 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!") # trueLes 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 # trueSymboles LaTeX
Il est possible dâutiliser les symboles LaTeX directement dans Julia.
# \beta [+ tabulation]
ÎČ = 10