Aki használt már Pythont, az szinte biztosan találkozott a listakomprehenziókkal, amelyek már a korai verziók óta a Python szintaxisának szerves részét képezik.
Egy ennyire kényelmes megoldás lassanként más nyelvekbe is utat tör magának, a Juliát is beleértve.
A Julia programozóinak a komprehenzió lehetőség, nem pedig kötelező eszköz, hiszen általában vannak alternatívák (broadcasting, magasabb rendű függvények stb.).
A komprehenzió azonban gyakran egyszerű, jól olvasható és hatékony módját kínálja egy tömb létrehozásának. Hogy végül használod-e, az végső soron személyes ízlés kérdése, akárcsak az, hogy miként vélekedsz a Pythonról a funkcionális nyelvekkel szemben.
A szintaxis nagyrészt a Pythonéból lett szinte változtatás nélkül átvéve, de kiegészült a többdimenziós tömbök kezelésével.
Nagyon pythonos, az opcionális if feltételt is beleértve.
julia> [x^2 for x in 1:3]
3-element Vector{Int64}:
1
4
9
julia> [x^2 for x in 1:3 if isodd(x^2)]
2-element Vector{Int64}:
1
9
A kimenet alakja a komprehenzió részleteitől függ: egyszerű esetekben jellemzően megegyezik a bemeneti kollekcióéval, egy if feltétel viszont Vectorrá lapítja.
julia> m
2×3 Matrix{Int64}:
1 2 3
4 5 6
julia> [x^2 for x in m]
2×3 Matrix{Int64}:
1 4 9
16 25 36
julia> [x^2 for x in m if isodd(x^2)]
3-element Vector{Int64}:
1
25
9
A Pythonhoz hasonlóan több for záradékunk is lehet különböző változókkal, akár ugyanazzal, akár eltérő bemeneti kollekcióval.
julia> [x * y for x in 1:3 for y in 4:6]
9-element Vector{Int64}:
4
5
6
8
10
12
12
15
18
julia> [x * y for x in 1:3 for y in 4:6 if isodd(x * y)]
2-element Vector{Int64}:
5
15
Ez az egymásba ágyazott ciklusokkal egyenértékű. A kimenet egydimenziós lesz, még mátrix bemenet esetén is.
julia> m
2×3 Matrix{Int64}:
1 2 3
4 5 6
julia> [x*y for x in m for y in m]
36-element Vector{Int64}:
1
4
2
5
(truncated output...)
Az előző szakaszban több for záradék szerepelt, amelyeket csupán szóközök választottak el egymástól.
Ebben a szakaszban egyetlen for van, a változókat pedig vessző választja el.
julia> [(x, y) for x in 1:3, y in 4:6]
3×3 Matrix{Tuple{Int64, Int64}}:
(1, 4) (1, 5) (1, 6)
(2, 4) (2, 5) (2, 6)
(3, 4) (3, 5) (3, 6)
A komprehenzió minden egyes változója egy-egy új dimenziót hoz létre a kimenetben, a változók minden lehetséges kombinációjához egy-egy bejegyzéssel.
A fenti példában x a sorok mentén növekszik lefelé, y pedig az oszlopok mentén jobbra.
Nagyobb dimenziók is lehetségesek, a kimenet olvashatóságára vonatkozó szokásos fenntartásokkal.
Az előző szakaszok a tömbkimenetre összpontosítottak, ahol a komprehenzió szögletes zárójelek [ ... ] közé kerül.
Ha a szögletes zárójeleket kerek zárójelekre ( ... ) cseréljük, valami más történik: a kapott objektum egy generator expression, egy lustán kiértékelt iterátor, amely igény szerint adja a következő értéket.
julia> g = ((x, y) for x in 1:3, y in 4:6)
Base.Generator{Base.Iterators.ProductIterator{Tuple{UnitRange{Int64}, UnitRange{Int64}}}, var"#9#10"}(var"#9#10"(), Base.Iterators.ProductIterator{Tuple{UnitRange{Int64}, UnitRange{Int64}}}((1:3, 4:6)))
# Indexing fails with a generator, the entries don't exist yet
julia> g[1, 2]
ERROR: MethodError: no method matching getindex(::Base.Generator{Base.Iterators.ProductIterator{Tuple{UnitRange{…}, UnitRange{…}}}, var"#9#10"}, ::Int64, ::Int64)
# conversion to array
julia> collect(g)
3×3 Matrix{Tuple{Int64, Int64}}:
(1, 4) (1, 5) (1, 6)
(2, 4) (2, 5) (2, 6)
(3, 4) (3, 5) (3, 6)
# generators are mainly designed for iteration
julia> [i * j for (i, j) in g]
3×3 Matrix{Int64}:
4 5 6
8 10 12
12 15 18
Ha egy komprehenzió eredményét rögtön tovább dolgozzuk fel, a generátor memóriatakarékos lehet: így nem kell eltárolni egy nagy közbenső tömböt.
Ha egy generátort függvényargumentumként adunk át, nem kell külön zárójelbe tennünk.
# inefficient
julia> v = [x^2 for x in 1:1e6];
julia> sum(v)
3.333338333335e17
# better - use a generator
julia> sum(x^2 for x in 1:1e6)
3.3333383333312755e17
A generátor szintaxisa ugyanaz, mint a komprehenzióé, csak a körülvevő zárójelekben tér el.
A generátorok a szótárkonstruktorokban is kényelmesek lehetnek.
julia> Dict(x => x^2 for x in 1:5)
Dict{Int64, Int64} with 5 entries:
5 => 25
4 => 16
2 => 4
3 => 9
1 => 1
Egy online divatbutikban dolgozol. Beugrik egy ötleted egy weboldalfunkcióra, ahol a felhasználónak szetteket ajánlunk. A lehetséges szettek, azok árai és az össze nem illő lehetőségek kiszűrése mind érdekesek.
Bár a következő feladatok megoldására többféle módszer is lehet, mindegyik megoldható egy comprehension használatával.
Valósítsd meg a clothingitem() függvényt, amely két Tuple-t kap: az egyik a categories, a másik a hozzájuk tartozó qualities.
A függvény egy Dict-et adjon vissza, amelyben a kulcsok a categories, az értékek pedig a qualities.
julia> categories = ("item_name", "price", "color", "base_color");
julia> qualities = ("Descriptive Name", 99.00, "Ochre Red", "red");
julia> clothingitem(categories, qualities)
Dict{String, Any} with 4 entries:
"price" => 99.0
"item_name" => "Descriptive Name"
"base_color" => "red"
"color" => "Ochre Red"
A függvényednek tetszőleges számú categories bejegyzést kezelnie kell.
Valósítsd meg a get_combinations() függvényt, amely egy felsőkből álló Tuple-t és egy alsókból álló Tuple-t kap.
A függvény a tuple-ök cartesian product-ját adja vissza kétdimenziós tömbként (azaz Matrix-ként).
Minden elem egy (top, bottom) kombináció, Tuple-ként.
A felsők a sorok mentén változnak, az alsók az oszlopok mentén.
julia> tops = (
Dict("item_name" => "Dress shirt"),
Dict("item_name" => "Casual shirt")
);
julia> bottoms = (
Dict("item_name" => "Jeans"),
Dict("item_name" => "Dress trousers")
);
julia> get_combinations(tops, bottoms)
2×2 Matrix{Tuple{Dict{String, String}, Dict{String, String}}}:
(Dict("item_name"=>"Dress shirt"), Dict("item_name"=>"Jeans")) (Dict("item_name"=>"Dress shirt"), Dict("item_name"=>"Dress trousers"))
(Dict("item_name"=>"Casual shirt"), Dict("item_name"=>"Jeans")) (Dict("item_name"=>"Casual shirt"), Dict("item_name"=>"Dress trousers"))
Minden ruhadarabhoz tartozik egy price mező, így hasznos lehet, ha össze tudjuk hasonlítani a szettek teljes árát.
Valósítsd meg a get_prices() függvényt, amely ruhakombinációk tömbjét kapja.
A függvény egy ugyanolyan alakú tömböt adjon vissza, amelyben a szettek árai a megfelelő helyükön szerepelnek.
julia> tops = (
Dict("item_name" => "Dress shirt", "base_color" => "blue", "price" => 35),
Dict("item_name" => "Casual shirt", "base_color" => "black", "price" => 20)
);
julia> bottoms = (
Dict("item_name" => "Jeans", "base_color" => "blue", "price" => 30),
Dict("item_name" => "Dress trousers", "base_color" => "black", "price" => 75)
);
julia> combomatrix = get_combinations(tops, bottoms);
julia> get_prices(combomatrix)
2×2 Matrix{Int}::
65 110
50 95
julia> filteredmatrix = filter_clashing(combomatrix)
1-element Vector{Tuple{Dict{String, Any}, Dict{String, Any}}}:
(Dict("price" => 20, "item_name" => "Casual shirt", "base_color" => "black"), Dict("price" => 30, "item_name" => "Jeans", "base_color" => "blue"))
julia> get_prices(filteredmatrix)
1-element Vector{Int}:
50
Minden ruhadarabnak van egy base_color mezője.
Ezzel a mezővel távolítsd el az összes olyan kombinációt, ahol a felső és az alsó alapszíne megegyezik.
Valósítsd meg a filter_clashing() függvényt, amely ruhakombinációk tömbjét kapja.
Add vissza a megfelelő kombinációk egydimenziós tömbjét (azaz Vector-t).
julia> tops = (
Dict("item_name" => "Dress shirt", "base_color" => "blue", "price" => 35),
Dict("item_name" => "Casual shirt", "base_color" => "black", "price" => 20)
);
julia> bottoms = (
Dict("item_name" => "Jeans", "base_color" => "blue", "price" => 30),
Dict("item_name" => "Dress trousers", "base_color" => "black", "price" => 75)
);
julia> combos = get_combinations(tops, bottoms);
julia> filter_clashing(combos)
1-element Vector{Tuple{Dict{String, Any}, Dict{String, Any}}}:
(Dict("price" => 20, "item_name" => "Casual shirt", "base_color" => "black"), Dict("price" => 30, "item_name" => "Jeans", "base_color" => "blue"))
Iratkozz fel az Exercism-re, hogy megtanuld és elsajátítsd a(z) Julia nyelvet 35 fogalom128 feladat segítségével, valódi emberi mentorálással, mindez ingyen.