Temat 3: Elementarne procedury oraz elementy składni
Wiersz komend Julii REPL
Tryby wiersza komend Julii:
julia - programowanie, tryb domyślny
help - dokumentacja, włączamy klawiszem ? pkg - zarzadca pakietów, włączamy klawiszem ] shell - wiersz komend systemu, włączamy klawiszem ; Powrót do trybu julia - klawisz <backspace> .
Najważniejsze polecenia pkg
add X - ściągnij z Githuba pakiet X i zainstaluj remove, rm X - usuń pakiet X
update X - zaktualizuj pakiet X
update, up - zaktualizuj wszystkie pakiety
Ładowanie pakietów X, Y, Z: using X, Y, Z w trybie julia
2-element Array{Float64,1}:
-0.3722813232690143 5.372281323269014 Jak działa using X :
Twórcy każdego pakietu ustalają, jakie komendy ma on eksportować. Po wpisaniu using X komendy te zostają załadowane do przestrzeni nazw.
Zawsze można, w przypadku konfliktów trzeba, doprecyzować używając X.nazwa_komendy .
Można też importować jedynie wybrane nazwy za pomocą polecenia import w stylu import X: komenda1, komenda2 .
Pisanie kodu
In [1]: # przykład
using LinearAlgebra A = [1 2; 3 4]
eigvals(A)
Out[1]:
W przeciwieństwie do Pythona wcięcia nie mają w Julii dużego znaczenia.
Komendy oddzielamy od siebie znakiem nowej linii lub średnikiem ; , ten drugi przy okazji instruuje też Julię, żeby nie wyświetlać wyniku na ekran w REPL.
Bloki kodu można tworzyć komendami begin ... end ( begin jest najczęściej domyślne) lub (... ; ... ; ...) .
4
6
9
Typy
Julia jest językiem opartym o dynamiczny system typów. Absolutnie wszystko w Julii ma typ, który jest dla kompilatora informacją, jakich procedur użyć dla przetwarzania konkretnych danych.
Typy w Julii tworzą drzewo, np. wierzchołek drzewa liczb to Number , Number rozdziela się na Complex oraz Real , Real dzieli się na Rational , Integer i inne, itd. itp.
Precyzowanie typów w Julii odbywa się operatorem ::
In [2]: # komendy wieloliniowe
f(x,y,z) = 2 f(1,
2, 3 ) 2 + 2
Out[2]:
In [3]: 2 +
if 1 > 0 4 end
Out[3]:
In [4]: # znaki unicode
ów = 2 λ = 2 δ₂ = 1 x¹ = 3 x¹^2
Out[4]:
Najważniejsze typy:
typy liczbowe
wartości logiczne Bool
znaki unicode Char , napisy String
tablice zwykłe Array oraz tablice specjalistyczne: bitowe, rzadkie, statyczne, itd.
braki w danych Missing , brak zwracanej wartości Nothing unie typów, np. Union{Bool,Nothing} - zmienna logiczna lub nic funkcje Function
symbole Symbol kod Julii Expr
typy DataType, UnionAll
Float64
DataType
Array{Int64,1}
true
true
false
true
In [5]: # podstawowy typ zmiennej sprawdzamy komendą typeof
typeof(2.0)
Out[5]:
In [6]: typeof(Int64)
Out[6]:
In [7]: typeof([1,2,3])
Out[7]:
In [8]: # sprawdzanie czy zmienna jest danego typu - isa
2.0 isa Float64
Out[8]:
In [9]: 2.0 isa Real
Out[9]:
In [10]: 2.0 isa Complex
Out[10]:
In [11]: 2.0 isa Number
Out[11]:
Liczby w Julii
Wszystkie liczby w Julii należą do nadtypu Number Typy całkowitoliczbowe ( Integer ):
Int64 - domyślny dla procesorów 64 bitowych
Int128, Int32, Int16, Int8 - do obliczeń na mniejszych/większych zakresach liczb UInt64, UInt32 itd. - całkowite nieujemne
BigInt - liczby całkowite nieograniczonego rozmiaru, są kosztowniejsze obliczeniowo Typy zmiennoprzecinkowe ( AbstractFloat ):
Float64 - domyślny
Float32, Float16 - mniejsza dokładność i zakres BigFloat - podobne do BigInt
Typy pochodne:
Rational - dokładne ułamki
Complex{Float64}, Complex{Int64} , itd. - liczby zespolone w których część rzeczywista i zespolona są typu Float64, Int64 itd.
7.38905609893065
Funkcje
Funkcja - w Julii zapis ogólnego schematu obliczeń, do którego następnie kompilator może dobrać konkretne procedury numeryczne. Takie doprecyzowanie nazywamy metodą
Zapisywanie procedur za pomocą funkcji jest dla kompilatora przydatną informacją, która zawsze zwiększa efektywność obliczeń.
Definiowane funkcji
In [12]: # stałe matematyczne
pi π im^2
ℯ^2 # exp(2)
Out[12]:
12
9.5
4
#1 (generic function with 1 method)
-0.9899924966004454
#5 (generic function with 1 method)
Używanie funkcji
0
In [13]: # 3 podstawowe metody
f(x) = x^2+4x f(2)
Out[13]:
In [14]: g(x) = begin y = 4
return x + y end
g(5.5)
Out[14]:
In [15]: function h(x) # równoważne h(x) = begin return x^2+4
end h(0)
Out[15]:
In [16]: x -> sin(2x)
Out[16]:
In [62]: j = x -> cos(3x)
j(1)
Out[62]:
In [18]: (x,y) -> x-y
Out[18]:
In [19]: # prosta aplikacja
f(x) = 2x - 4 f(2)
Out[19]:
6
0.7962627076842108
4-element Array{Int64,1}:
-2 0 2 4
(4, 4)
2×2 Array{Int64,2}:
0 0 0 0
Najważniejsze funkcje matematyczne:
round, floor, ceil, sign - zaokrąglenia, znak
÷ (\div<tab>), %, mod, mod1 - dzielenie całkowitoliczbowe, warianty modulo abs, real, imag, - moduł, część rzeczywista, zespolona
sqrt, ^, - pierwiastek, potęga exp, cis, - funkcje
log, log2, log10, - logarytmy
sin, cos, tan, sinh, cosh, tanh, - funkcje trygonometryczne, hiperboliczne sincos, sinpi, cospi, sinc, - warianty trygonometrycznych
factorial, binomial - silnia, symbol Newtona In [20]: 5 |> f # to samo co f(5)
Out[20]:
In [21]: 3.0 |> sin |> f |> tan |> cos |> display # display(cos(tan(f(sin(x)))))
In [22]: # aplikowanie wektorowe
f.([1, 2, 3, 4])
Out[22]:
In [23]: (1,2) .+ (3,2)
Out[23]:
In [24]: # funkcje zmieniające argumenty - wykrzyknik !
x = [1 2; 3 4]
fill!(x,0) # pobrał x i zmienił x
Out[24]:
ex, eix
24.0
Makra
Makro - funkcja pobierająca kod i zwracająca zmodyfikowany kod, w Julii zawsze zaczynają się od @
Metaprogramowanie - dział programowania zajmujący się analizą i przetwarzaniem kodu W Julii metaprogramowanie jest bardzo rozwinięte, język ten jest w stanie bezpośrednio przetwarzać własny kod. Jest on interpretowany jako ciąg wyrażeń symbolicznych.
Przydatne podstawowe makra:
+(x::T, y::T) where T<:Union{Int128, Int16, Int32, Int64, Int8, UInt128, UInt16, UInt32, UInt64, UInt8} in Base at int.jl:86
+(x::Float64, y::Float64) in Base at float.jl:401
0.002876 seconds (10 allocations: 7.649 MiB) 499941.5967836991
x = 2 + 2 = 4 4
Variables
#self#::Core.Compiler.Const(+, false) x::Int64
y::Int64 Body::Int64
1 ─ %1 = Base.add_int(x, y)::Int64 In [25]: # więcej matematycznych funkcji
using SpecialFunctions gamma(5)
Out[25]:
In [26]: @which 1+1
Out[26]:
In [27]: @which 2.0 + 2.0
Out[27]:
In [28]: @time sum(rand(10^6))
Out[28]:
In [29]: @show x = 2 + 2
Out[29]:
In [30]: @code_warntype 2+4^2
└── return %1
.text
; ┌ @ int.jl:86 within `+' pushq %rbp
movq %rsp, %rbp
leaq (%rcx,%rdx), %rax popq %rbp
retqnopw (%rax,%rax)
; └
BenchmarkTools.Trial:
memory estimate: 781.33 KiB allocs estimate: 2
---
minimum time: 106.800 μs (0.00% GC) median time: 320.400 μs (0.00% GC) mean time: 387.234 μs (13.16% GC) maximum time: 7.950 ms (83.31% GC) ---
samples: 10000 evals/sample: 1
Instrukcje warunkowe
Operatory logiczne i porównania
! & | ⊻ - nie, oraz, lub, albo ( \xor<tab> )
|| && - short circuit lub, oraz
> < >= <= - nierówności
== === - równość, identyczność zmiennej in - czy należy do zbioru
'b': ASCII/Unicode U+0062 (category Ll: Letter, lowercase) In [31]: @code_native 2+2
In [32]: using BenchmarkTools
@benchmark prod(rand(10^5))
Out[32]:
In [33]: # if
x = 5 if x > 7
'a' elseif x < 6
'b' else
'c' end Out[33]:
'a': ASCII/Unicode U+0061 (category Ll: Letter, lowercase)
'd': ASCII/Unicode U+0064 (category Ll: Letter, lowercase)
Pętle
Pętla while
Schemat
while cond ...
end
cond - wyrażenie lub zmienna logiczna, tj. Bool
2 48 16
In [34]: # operator trójwartościowy
x = 4
x > 0 ? 'a' : 'b'
Out[34]:
In [35]: # w bibliotece stanardowej nie ma komendy switch
# pakiet Match udostępnia znacznie potężniejszy odpowiednik
using Match x = 20
@match x begin 1 => 'a' 2 || 3 => 'b' 4:7 => 'c'
n::Int, if n % 10 == 0 end => 'd' _ => 'e'
end Out[35]:
In [36]: # while
k = 1
while k < 100 k *= 2
k |> println end
3264 128
Pętla for
Schemat
for x in iter ...
end
iter - iterator, dowolna zmienna, z której można wypisać wszystkie elementy
(1, 1) (1, 2) (1, 3) (1, 4) (1, 5) (2, 2) (2, 3) (2, 4) (2, 5) (3, 3) (3, 4) (3, 5) (4, 4) (4, 5) (5, 5)
Prosta wizualizacja
Najprostszym narzędziem do robienia podstawowych wykresów i grafiki jest pakiet Plots wraz z komendą plot .
Składnia:
plot(xs,ys,opcje) xs - wektor iksów, ys - wektor igreków,
opcje - wymieniane po przecinku modyfikatory wyglądu wykresu.
"Wektor" - dowolna zmienna, którą możemy interpretować jako kolumnowy wektor matematyczny, w szczególności: tablice, zakresy.
Wynik: łamana łącząca punkty (xs[1],ys[1]), (xs[2],ys[2]), ...
In [63]: # pętle wielokrotne
for j in 1:5, k in j:5 (j,k) |> println end
plot!(xs,ys,opcje)
Dorysowuje łamaną do aktualnie wyświetlanego wykresu oraz zmienia jego wygląd.
plot!(opcje) tylko zmienia wygląd scatter(xs,ys,opcje)
Nie rysuje łamanej, lecz pojedyncze punkty.
scatter!(xs,ys,opcje) Dorysowuje punkty.
In [1]: using Plots # wcześniej trzeba zainstalować używając Pkg
xs = 0:0.01:2pi ys = sin.(xs) plot(xs,ys,
linecolor = :green, title = "sinus", xlabel = "t", ylabel = "sin(t)", linestyle = :dash )
plot!(xs,cos.(xs), linecolor = :red )
Out[1]:
In [2]: # wykres samych ys
ys = rand(1:10,10)
plot(ys) # xs = [1,2,3,...]
Out[2]:
In [8]: xs = 20:30
ys = rand(-5:5,10) scatter(xs,ys,
markercolor = :yellow, markersize = 5,
markerstrokecolor = :red, markerstrokewidth = 0 )
Proste typy danych
ciąg bitów wraz z metodami ich przetwarzania opisują wartość bez struktury wewnętrznej zaimplementowane na niskim poziomie
Znane przykłady: liczby całkowite Int64 , zmiennoprzecinkowe Float64 .
Wartości logiczne Bool
instrukcje warunkowe w Julii przyjmują wyłącznie wartości Bool w arytmetyce zachowują się jak 1 lub 0
Deklaracja: true lub false .
6
7 Out[8]:
In [9]: # arytmetyka true + 5
Out[9]:
In [11]: false + 7
Out[11]:
NaN
NaN
0.0
0.0
Znaki Char
reprezentują pojedynczy znak unicode
dodawanie oraz odejmowanie przesuwa znak na liście unicode Deklaracja: apostrofy `a` , `ł` , `λ` , itp.
'a': ASCII/Unicode U+0061 (category Ll: Letter, lowercase)
'e': ASCII/Unicode U+0065 (category Ll: Letter, lowercase)
'r': ASCII/Unicode U+0072 (category Ll: Letter, lowercase)
'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) In [12]: 0*Inf
Out[12]:
In [13]: 0*NaN
Out[13]:
In [14]: false*Inf
Out[14]:
In [15]: false*NaN # silne zero
Out[15]:
In [17]: # przesuwanie znaków
'a'
Out[17]:
In [19]: 'a' + 4
Out[19]:
In [20]: 'w' - 5
Out[20]:
In [23]: # zakresy znaków
'a':'k' .|> display;
'd': ASCII/Unicode U+0064 (category Ll: Letter, lowercase) 'e': ASCII/Unicode U+0065 (category Ll: Letter, lowercase) 'f': ASCII/Unicode U+0066 (category Ll: Letter, lowercase) 'g': ASCII/Unicode U+0067 (category Ll: Letter, lowercase) 'h': ASCII/Unicode U+0068 (category Ll: Letter, lowercase) 'i': ASCII/Unicode U+0069 (category Ll: Letter, lowercase) 'j': ASCII/Unicode U+006A (category Ll: Letter, lowercase) 'k': ASCII/Unicode U+006B (category Ll: Letter, lowercase)
'9': ASCII/Unicode U+0039 (category Nd: Number, decimal digit) '7': ASCII/Unicode U+0037 (category Nd: Number, decimal digit) '5': ASCII/Unicode U+0035 (category Nd: Number, decimal digit) '3': ASCII/Unicode U+0033 (category Nd: Number, decimal digit) '1': ASCII/Unicode U+0031 (category Nd: Number, decimal digit)
Symbole Symbol
służą do itentyfikowania nazw, metek reprezentują nazwy zmiennych w Julii
często używane np. do wyboru opcji ze skończonej listy
wydajniejsze od napisów String , nie przechowują wszystkich znaków, a jedynie jednoznaczny identyfikator
Deklaracja: pojedynczy dwukropek :sym
Symbol
nie wybrano A lub B
Złożone typy danych
na zmienną typu złożonego składa się:
In [25]: '9':-2:'1' .|> display;
In [27]: # przykładowe zastosowanie
x = :symbol2 x |> typeof
Out[27]:
In [30]: function wybór(opcja) if opcja == :A
"wybrano A" |> println elseif opcja == :B
"wybrano B" |> println else
"nie wybrano A lub B" |> println end
end
wybór(:D)
pewna liczba zmiennych prostych typu liczby, znaki, wartości logiczne itp.
specyficzne metody ich przetwarzania
typy złożone są podobne do klas w językach obiektowych
typy złożone dzielimy na modyfikowalne (mutable) i niemodyfikowalne (unmutable) Znane przykłady:
Complex - składa się z części rzeczywistej oraz urojonej z.im, z.re Rational - składa się z licznika oraz mianownika r.num, r.den
6
Zakresy UnitRange, StepRange, LinRange, ...
niemodyfikowalne
odpowiadają skończonym ciągom arytmetycznym
zachowują się podobnie do tablic, jednak zamiast zapisywać wartości wszystkich elementów w pamięci zapisują parametry reguły, na podstawie której można je wygenerować, kiedy są potrzebne
Składnia:
a:b - liczby , - największa liczba całkowita nie większa niż
a:c:b - liczby , - największa liczba postaci nie
większa od
LinRange(a,b,n) - liczb równomiernie rozmieszczonych na odcinku , tzn. pierwsza to , ostatnia to , są umieszczone co .
Opcjonalnie range , ale rzadko używana.
1.0:1.0:5.0
20 1816 14 In [31]: x = 5
y = x + 1 # kompilator zastąpi x -> 5, y = 5 + 1, y = 6
Out[31]:
a, a + 1, a + 2, . . . , c′ b′ b
a, a + c, a + 2c, a + 3c, . . . b′ b′ a+ kc b
n [a, b]
a b (n − 1)/(b − a)
In [32]: # przykłady
1:5.5 # 5.5 wypada Out[32]:
In [34]: 20:-2:13 .|> display;
7-element LinRange{Float64}:
0.0,0.833333,1.66667,2.5,3.33333,4.16667,5.0
9-element Array{Float64,1}:
0.0
0.7071067811865475 1.0
0.7071067811865476 1.2246467991473532e-16 -0.7071067811865475 -1.0
-0.7071067811865477 -2.4492935982947064e-16
3:2:21
Tablica Array
modyfikowalna
reprezentuje grupę zmiennych identycznego typu zapisanych obok siebie w pamięci mogą być deklarowane bezpośrednio za pomocą [] lub NazwaTypu[] :
[a, b, c, d, ...] - wektor 1D z wartościami a, b, c, d, ...
[a b c ... ; d e f... ; ...] - macierz o wierszach a b c ... , poniżej d e f ... itd.
w tablicy zapisane są:
typ komórek eltype jej kształt size
adres w pamięci pointer Schemat typu:
Array{T,N}
T - typ wartości w komórkach N - wymiar tablicy
Tablice 1D Array{T,1} to inaczej Vector{T} , tablice 2D Array{T,2} to inaczej Matrix{T} .
In [36]: LinRange(0,5,7)
Out[36]:
In [37]: # zakresy zachowują się jak wektory kolumnowe
sin.(0:pi/4:2pi)
Out[37]:
In [38]: (1:2:20) .+ 2
Out[38]:
2×2 Array{Int64,2}:
2 1 3 4
2×2 Array{Rational,2}:
1//1 2//1 7//1 9//1
(2, 2)
Rational
Ptr{Rational} @0x00000000177dad60
3-element Array{Any,1}:
'z': ASCII/Unicode U+007A (category Ll: Letter, lowercase) 4
[3 3 5]
1×3 Array{Int64,2}:
3 3 5 In [39]: # przykłady
[2 1; 3 4]
Out[39]:
In [41]: A = Rational[1 2; 7 9]
Out[41]:
In [42]: size(A)
Out[42]:
In [43]: eltype(A)
Out[43]:
In [44]: pointer(A)
Out[44]:
In [49]: # dynamiczne modyfikacje tablic
tab = [] # Int8[] lepiej wydajnościowo push!(tab,'z')
push!(tab,4)
push!(tab,[3 3 5]) # nie znamy typu elementów, nie mamy zaalokowanej pamięci, wolne!
# tylko kiedy nie znamy rozmiaru tablicy Out[49]:
In [50]: tab[3]
Out[50]:
In [51]: pop!(tab) tab
2-element Array{Any,1}:
'z': ASCII/Unicode U+007A (category Ll: Letter, lowercase) 4
5-element Array{Any,1}:
'z': ASCII/Unicode U+007A (category Ll: Letter, lowercase) 4
'a': ASCII/Unicode U+0061 (category Ll: Letter, lowercase) (1, 1)
15
Użycie konstruktora: Array{T}(undef,n,m,...) - alokuje komórek w pamięci na zmienne typu T
Array{T}(undef,n) - wektor 1D Array{T}(undef,n,m) - macierz 2D Array{T}(undef,n,m,o) - macierz 3D, itd.
3×2 Array{Char,2}:
'\x0a\x23\x3c\x60' '\0'
'\0' '\x0a\x43\xae\xa0' '\x0a\x23\x39\xa0' '\0'
5-element Array{Int64,1}:
169503776 169503776 145293424 169503776 145293488
Najważniejsze komendy tworzące tablice
Macierze wypełnione identycznymi wartościami:
zeros([T=Float64],n,m,...) - macierz z zerami typu T , domyślny jest Float64 , wymiaru
ones([T=Float64],n,m,...) - jak wyżej z jedynkami
falses(n,m,...) - macierz logiczna wypełniona false wymiaru trues(n,m,...) - jak wyżej wypełniona true
fill(x,n,m,...) - macierz wypełniona komórkami z kopiami wartości x wymiaru Out[51]:
In [52]: append!(tab,['a' (1,1) 15]) # wstawia tablicę element po elemencie
Out[52]:
n× m × …
In [53]: # użycie konstruktora, najszybsze
Array{Char}(undef, 3, 2) Out[53]:
In [54]: Array{Int64}(undef,5) # przypadkowe bity, które były w pamięci
Out[54]:
n× m × …
n× m × …
n× m × …
2×4 Array{Float16,2}:
0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0
4×4 Array{Float64,2}:
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 1.0
1×4 Array{Int64,2}:
1 1 1 1
2×4 BitArray{2}:
0 0 0 0 0 0 0 0
2×2 Array{Tuple{Int64,Int64},2}:
(1, 1) (1, 1) (1, 1) (1, 1)
3×2 Array{Array{Int64,2},2}:
[1 2] [1 2]
[1 2] [1 2]
[1 2] [1 2]
Inne przydatne komendy:
rand(zbiór,n,m,...) - macierz z losowymi wartościami ze zbiór
similar(A) - alokuje miejsce na tablicę identycznego wymiaru i typu jak A collect(iter) - zbiera elementy iteratora i zapisuje do tablicy
copy(A) - tworzy kopię tablicy A w nowym miejscu w pamięci
1×3 Array{Int64,2}:
In [55]: # przykłady
zeros(Float16,2,4)
Out[55]:
In [56]: ones(4,4) # Float64 domyślny
Out[56]:
In [57]: ones(Int64,1,4)
Out[57]:
In [59]: falses(2,4)
Out[59]:
In [60]: fill((1,1),2,2)
Out[60]:
In [61]: fill([1 2],3,2)
Out[61]:
In [62]: # przykłady
A = [2 3 4]
Out[62]:
2 3 4
1×3 Array{Int64,2}:
146251976 145872112 146082016
5-element Array{Int64,1}:
1 2 3 4 5
13-element Array{Float64,1}:
25.0 20.25 16.0 12.25 9.0 6.25 4.0 2.25 1.0 0.25 0.0 0.25 1.0
4×4 Array{Int64,2}:
2 10 5 4 1 6 8 7 4 6 7 1 5 3 4 2
4×4 Array{Int64,2}:
0 10 5 4 1 6 8 7 4 6 7 1 5 3 4 2
4×4 Array{Int64,2}:
In [63]: similar(A) # ten sam rozmiar i typ
Out[63]:
In [64]: 1:5 |> collect
Out[64]:
In [65]: collect(i^2 for i in -5:0.5:1)
Out[65]:
In [67]: C = rand(1:10,4,4)
D = C D
Out[67]:
In [69]: D[1,1] = 0 D
Out[69]:
In [70]: C # to samo miejsce w pamięci co D
Out[70]:
0 10 5 4 1 6 8 7 4 6 7 1 5 3 4 2
4×4 Array{Int64,2}:
0 10 5 4 1 6 8 7 4 6 7 1 5 3 4 2
4×4 Array{Int64,2}:
0 15 5 4 1 6 8 7 4 6 7 1 5 3 4 2
4×4 Array{Int64,2}:
0 10 5 4 1 6 8 7 4 6 7 1 5 3 4 2
Dostęp do elementów tablicy
A[i,j,...] - komórka o współrzędnych Uwaga! Indeksy zaczynają się od jedynki.
end - ostatnia komórka wzdłuż danego wymiaru, np. v[end] to ostatni element wektora v , A[4,end] to element z czwartego wiersza i ostatniej kolumny
3
2×2 Array{Int64,2}:
1 2 3 4
In [71]: E = copy(C) E
Out[71]:
In [72]: E[1,2] = 15 E
Out[72]:
In [73]: C # niezależne od E
Out[73]:
ij. . .
In [76]: # przykłady
A = [1 2; 3 4]
A[end,1]
Out[76]:
In [75]: A
Out[75]:
Wycinki tablicy
A[zakres1,zakres2,...] - wybiera wycinek z kolumnami wymienionymi w zakres1 , wierszami wymienionymi w zakres2 ...
Wstawienie dwukropa : zamiast zakresu oznacza "wybierz wszystko".
10×10 Array{Int64,2}:
1 2 3 4 5 6 7 8 9 10 2 4 6 8 10 12 14 16 18 20 3 6 9 12 15 18 21 24 27 30 4 8 12 16 20 24 28 32 36 40 5 10 15 20 25 30 35 40 45 50 6 12 18 24 30 36 42 48 54 60 7 14 21 28 35 42 49 56 63 70 8 16 24 32 40 48 56 64 72 80 9 18 27 36 45 54 63 72 81 90 10 20 30 40 50 60 70 80 90 100
4×3 Array{Int64,2}:
4 5 6 8 10 12 12 15 18 16 20 24
2×4 Array{Int64,2}:
4 16 28 40 6 24 42 60
10-element Array{Int64,1}:
4 8 12 16 20 24 28 32 36 40
4-element Array{Int64,1}:
In [77]: #przykłady
A = (1:10) .* (1:10)'
Out[77]:
In [78]: A[1:4,4:6]
Out[78]:
In [79]: A[4:2:7,1:3:end]
Out[79]:
In [80]: A[:,4] # czwarta kolumna
Out[80]:
In [81]: A[10:-2:3,3] # od tyłu
Out[81]:
30 24 18 12
Uwaga! Wycinki domyślnie kopiują zadane komórki do nowej tablicy. Jeżeli chcemy tego uniknąć używamy funkcji view(A,zakres1,zakres2,...) lub dopisujemy @view .
Wyjątek: A[zakres1,zakres2,...] = ... modyfikuje macierz A
2×2 Array{Int64,2}:
1 2 4 5
2×2 Array{Int64,2}:
0 0 0 0
3×3 Array{Int64,2}:
1 2 3 4 5 6 7 8 9
3×3 Array{Int64,2}:
1 2 3 4 5 5 7 8 5
3×3 Array{Int64,2}:
-1 -1 3 -1 -1 5 7 8 5 In [82]: # przykłady
A = [1 2 3; 4 5 6; 7 8 9]
x = A[1:2,1:2]
x
Out[82]:
In [83]: x .= 0 x
Out[83]:
In [84]: A # niezmienione, bo x to kopia
Out[84]:
In [87]: A[2:3,3] .= 5 A
Out[87]:
In [88]: y = view(A,1:2,1:2)
y .= -1
A # A się zmieniła, y odwołuje się do A
Out[88]:
3×3 Array{Int64,2}:
-1 7 3 -1 7 5 7 8 5
Napis String
niemodyfikowalny
podobny do tablicy Char , ale w kodowaniu unicode poszczególne znaki mogą zajmować różną ilość bajtów w pamięci
Składnia deklaracji "napis"
"wyrażenie 2 + 2 = 4"
"zmienna iks jest równa 42"
'o': ASCII/Unicode U+006F (category Ll: Letter, lowercase)
'ó': Unicode U+00F3 (category Ll: Letter, lowercase) In [90]: z = @view A[1:2,2]
z .= 7
A # zmienione
Out[90]:
In [91]: # dynamiczne tworzenie napisów, znak $
"wyrażenie 2 + 2 = $(2+2)"
Out[91]:
In [92]: x = 42
"zmienna iks jest równa $x"
Out[92]:
In [93]: # dostęp do komórek napisów
s = "kaloryfer"
s[4]
Out[93]:
In [94]: # znaki poza ASCII wywołują problemy
z = "ówczesny"
z[1]
Out[94]:
StringIndexError("ówczesny", 2) Stacktrace:
[1] string_index_err(::String, ::Int64) at .\strings\string.jl:12
[2] getindex_continued(::String, ::Int64, ::UInt32) at .\strings\string.jl:22 0
[3] getindex(::String, ::Int64) at .\strings\string.jl:213 [4] top-level scope at In[95]:1
[5] include_string(::Function, ::Module, ::String, ::String) at .\loading.jl:
1091
'w': ASCII/Unicode U+0077 (category Ll: Letter, lowercase)
A la
m a ko ta
Krotki Tuple, NamedTuple
niemodyfikowalne
uporządkowane zbióry n zmiennych, które mogą być różnych typów w Tuple pola mają jedynie numery, w NamedTuple mają swoje nazwy Składnia
(a,b,c,d,...) - zwykła
(x = a, y = b, z = c, ...) - nazwana
(1, 'a', "tutaj")
In [95]: z[2] # dostęp do 2 bajtu napisu, ale 'ó' zajmuje więcej niż 1 bajt
In [97]: z[3] # 'w' zaczyna się od 3 bajtu
# dopóki znaki są ASCII indeksowanie [] jest ok
Out[97]:
In [98]: for s in "Ala ma kota" # dostęp do znaków po kolei s |> println
end
In [99]: # przykładowa krotka i jej typ
x = (1,'a',"tutaj")
Out[99]:
Tuple{Int64,Char,String}
'a': ASCII/Unicode U+0061 (category Ll: Letter, lowercase)
(A = 4, B = [1, 2])
NamedTuple{(:A, :B),Tuple{Int64,Array{Int64,1}}}
4
2-element Array{Int64,1}:
1 2
(imię = "Jan", nazwisko = "Kowalski", wiek = 32)
(4, 2)
In [100… x |> typeof
Out[100…
In [102… # dostęp do elementów
x[2]
Out[102…
In [103… # krotka nazwana
y = (A = 4, B = [1, 2]) y
Out[103…
In [104… y |> typeof
Out[104…
In [105… y.A
Out[105…
In [106… y.B # przydatne do baz danych
Out[106…
In [107… # przykład bazodanowy
(imię = "Jan", nazwisko = "Kowalski", wiek = 32)
Out[107…
In [108… # funkcje zwracające wiele zmiennych
f(x) = (x+1,x-1) f(3)
Out[108…
'a': ASCII/Unicode U+0061 (category Ll: Letter, lowercase)
4
2-element Array{Int64,1}:
1 2
"napis"
(6, 4)
6
Słownik Dict
modyfikowalny
odpowiada grupie zmiennych identyfikowalnych po kluczach Składnia
Dict( k1 => val1, k2 => val2, ... )
Dict{Any,Int64} with 3 entries:
(1, 2) => -1
In [110… # rozpakowywanie w miejscu
a, b = ('a',4,15) a
Out[110…
In [111… b
Out[111…
In [112… c, d = [1,2], "napis"
c
Out[112…
In [113… d
Out[113…
In [114… x, = f(5)
Out[114…
In [115… x # zignorowało drugą zwracaną wartość
Out[115…
In [116… # przykłady
d = Dict('a' => 4, 42 => 0, (1,2) => -1)
Out[116…
42 => 0
4
-1
Dict{Any,Int64} with 4 entries:
(1, 2) => -1 42 => 0 'a' => 4 'b' => -5
4
Dict{Any,Int64} with 3 entries:
(1, 2) => -1 42 => 0 'b' => -5
Generator Generator
niemodyfikowalny
uogólnienie zakresów na skończone lub nieskończone ciągi inne niż arytmetyczne brak swobodnego dostępu do elementów ( gen[k] ), ale to iterator
jego składnię warto skojarzyć z matematycznym definiowaniem zbioru
Składnia
(wyrażenie(x) for x in iter) - pojedynczy generator
(wyrażenie(x,y,...) for x in iter1 for y in iter2, ...) - wielokrotny iterator (wyrażenie(x,y,...) for x in iter1, y in iter2, ...) - jak wyżej, ale zapisuje też kształt
(wyrażenie(x,y,z) for x in iter if warunek) - generator z warunkowaniem In [117… d['a']
Out[117…
In [118… d[(1,2)]
Out[118…
In [119… # komendy push! oraz pop!
push!(d,'b'=> -5)
Out[119…
In [120… pop!(d,'a')
Out[120…
In [121… d # nie ma rekordu 'a'
Out[121…
{f(x, y): x ∈ A, y ∈ B}
1 01 49 16
(1, -1) (1, 0) (2, -2) (2, -1) (2, 0) (3, -3) (3, -2) (3, -1) (3, 0) (4, -4) (4, -3) (4, -2) (4, -1) (4, 0) (5, -5) (5, -4) (5, -3) (5, -2) (5, -1) (5, 0)
5×2 Array{Tuple{Int64,Int64},2}:
(-1, 16) (-1, 25) (0, 16) (0, 25) (1, 16) (1, 25) (2, 16) (2, 25) (3, 16) (3, 25)
0 12
210
In [126… # przykłady
(i^2 for i in -1:4) .|> display;
In [125… ( (i,j) for i in 1:5 for j in -i:0 ) .|> display;
In [128… collect( (i,j^2) for i in -1:3, j in 4:5) # ma kształt macierzy 2D
# iteratory nie mogą zależeć od siebie, np j in -i:0 byłoby źle Out[128…
In [130… (i for i in -10:10 if -1 < i < 3) .|> display;
In [131… # komendy sum, cumsum, prod, minimum
sum(i for i in 1:20)
Out[131…
0.04000000000000003
In [132… minimum(i^2 for i in LinRange(-2,1,6))
Out[132…