# DP25a, mintazéhá, 2025. október ## Személyi adatok Az Elixir-cellában lévő kódba írja be a kért adatokat: név, NEPTUN-kód és hely (pl 307b16).
```elixir defmodule Personal do @nev "" @neptun "" @hely "" def check() do unless @nev != "" and @neptun != "" and @hely != ""do "Írja be a kért adatokat!" else "Köszönjük az adatok beírását!" end end end Personal.check() ```
```elixir defmodule Personal do @nev "" @neptun "" @hely "" def check() do unless @nev != "" and @neptun != "" and @hely != "" do "Írja be a kért adatokat!" else "Köszönjük az adatok beírását!" end end end Personal.check() ``` ## A virtuális gépről és környezetről A zárthelyit Oracle Virtualboxban futó Ubuntu 24.04 operációs rendszer alatt íratjuk. A felhasználó neve `dp`, jelszava `dpfpzarthelyi`. A virtuális gép indulásakor a belépés automatikus, a Livebook is elindul, a jelszó azonos a `dp` felhasználó jelszavával. Ha a Livebook nem futna, egy virtuális terminálban * indítsa el a `/home/ubuntu/run_livebook.sh` szkriptet, vagy * adja ki a `livebook server lb` parancsot – az `lb` mappanév megadása fontos a böngészőablak automatikus megnyitásához. A Livebook szerver indítása elindítja a Firefox böngészőt is. A Livebookon kívül két további fül is megnyílik. Az egyik az Elektronikus TanárSegéd, ETS , a másik egy kivonat az Elixir dokumentációból. Más szervert nem lehet elérni a virtuális gépről. __Bármilyen más online felület használata TILOS, bármilyen eszközről!__ ## A beadásról A zárthelyi megoldását az ETS-sel kell beadni. Csak olyan `.exs` fájlt adjon be, ami a Livebookban futtatható, akkor is, ha az eredmény hibás. 1. A megoldás elmentéséhez kattintson a lap tetején a bal felső sarokban található három függőleges pontra, majd az *Export* menüpontra. Válassza ki az *IEX session* fület, majd kattintson a *Download source* ikonra. Az elmentett fájl (valószínűleg) a böngésző által használt Downloads/Letöltések mappába kerül. 2. Lépjen be az ETS-be. A zárthelyi megoldását a *Feladatbeadás* menüpont *Elixir ...zéhá* sorában kell feltöltenie. A feltöltendő fájl neve bármi lehet, az ETS át fogja nevezni `zh1.exs`-re. 3. Ha a beadott `.exs` fájlt az ETS nem tudja lefordítani, javítsa ki a hibát, és adja be újra. A legutolsó beadást tekintjük érvényesnek. 4. A beadott megoldást akkor is értékeljük – pontlevonások mellett – ha nem sikerült hibátlanul leforduló programot feltöltenie. __Fontos! Nem a `*.livemd`, hanem a `*.exs` fájlt kell felölteni!__ ## 1. feladat: Egyklózos, nemrekurzív és magasabb rendű függvények írjon egy-egy egyklózos, nemrekurzív függvényt az alábbi feladatok (`f1`, `f2`, `f3`) megoldására. Segédfüggvényt nem definiálhat. Javasoljuk a megfelelő helyeken a `for`-komprehenzió, valamint az `Enum.zip/2` és az `Enum.split_while/2` használatát.
```elixir defmodule T1 do def f(i, xs) do # @spec f1(xs :: [any()]) :: rs :: [any()] # Az xs lista hárommal *nem* osztható indexű elemeiből álló lista zs, az # elemek eredeti sorrendjében. Indexelés 0-tól. Az xs lista üres is lehet. (3 pont) f1 = fn(xs) -> _ = xs; nil end # @spec f2(coll :: [integer()] | Range.t()) :: s :: integer() # A coll számlista vagy tartomány páros értékű elemeinek összege s (3 pont) f2 = fn(coll) -> _ = coll; nil end # @spec f3(xs::[integer()]) :: n::integer() # Az xs lista monoton növekvő elemekből álló, lehető leghosszabb prefixuma n # hosszú. Azaz xs első n eleme monoton növekvő sorozatot alkot, és az xs vagy # pontosan n elemből áll, vagy az (n+1)-edik eleme kisebb az előtte # állónál. Feltételezheti, hogy xs nem üres. (4 pont) f3 = fn(xs) -> _ = xs; nil end case i do 1 -> f1.(xs) 2 -> f2.(xs) 3 -> f3.(xs) 4 -> f4.(xs) end end end (T1.f(1, [1,-4,5,6,"5",-3,12,11,7,4]) === [-4,5,"5",-3,11,7]) |> IO.inspect() (T1.f(1, [:a,4]) === [4]) |> IO.inspect() (T1.f(1, [:b]) === []) |> IO.inspect() (T1.f(1, [0,:c,-1]) === [:c,-1]) |> IO.inspect() (T1.f(1, []) === []) |> IO.inspect() (T1.f(2, 1..10 // 1) === 30) |> IO.inspect() (T1.f(2, 10..1 // -3) === 14) |> IO.inspect() (T1.f(2, [-7, -4, -2, -1, 0, 4, 9, 12, 14, 17, 26]) === 50) |> IO.inspect() (T1.f(3, [6]) === 1) |> IO.inspect() (T1.f(3, [6, 7, 8, 6, 7, 8, 6, 7, 9]) === 3) |> IO.inspect() (T1.f(3, [2, 2, 2, 3, 3, 3]) === 6) |> IO.inspect() (T1.f(3, [-1, -2, -2]) === 1) |> IO.inspect() (T1.f(3, [3, 2, 1, 0]) === 1) |> IO.inspect() (T1.f(3, [1, 2, 3, 4, 5, 6, 7]) === 7) |> IO.inspect() ```
```elixir ``` ```elixir (T1.f(1, [1,-4,5,6,"5",-3,12,11,7,4]) === [-4,5,"5",-3,11,7]) |> IO.inspect() (T1.f(1, [:a,4]) === [4]) |> IO.inspect() (T1.f(1, [:b]) === []) |> IO.inspect() (T1.f(1, [0,:c,-1]) === [:c,-1]) |> IO.inspect() (T1.f(1, []) === []) |> IO.inspect() ``` ```elixir (T1.f(2, 1..10 // 1) === 30) |> IO.inspect() (T1.f(2, 10..1 // -3) === 14) |> IO.inspect() (T1.f(2, [-7, -4, -2, -1, 0, 4, 9, 12, 14, 17, 26]) === 50) |> IO.inspect() ``` ```elixir (T1.f(3, [6]) === 1) |> IO.inspect() (T1.f(3, [6, 7, 8, 6, 7, 8, 6, 7, 9]) === 3) |> IO.inspect() (T1.f(3, [2, 2, 2, 3, 3, 3]) === 6) |> IO.inspect() (T1.f(3, [-1, -2, -2]) === 1) |> IO.inspect() (T1.f(3, [3, 2, 1, 0]) === 1) |> IO.inspect() (T1.f(3, [1, 2, 3, 4, 5, 6, 7]) === 7) |> IO.inspect() ``` ## 2. feladat: Zsákok metszete A zsák (angolul bag vagy multiset) olyan adatstruktúra, amelyben az elemek sorrendje – a halmazhoz hasonlóan – érdektelen, ám – a halmazzal ellentétben – ugyanaz az elem többször is előfordulhat benne. Egy elem előfordulásainak számát multiplicitásnak nevezzük. Elixirben egy zsákot pl. map-pel ábrázolhatunk, ahol az elem a kulcs, az érték pedig a multiplicitása. Az kulcs tetszőleges típusú érték lehet, a multiplicitás pozitív egész szám. Írjon olyan függvényt `metszet` néven, amely két zsák metszetét adja eredményül. A zsákok üresek is lehetnek. __Nem használhatja a `Map.intersect/3` függvényt.__ Tipp: a `for` komprehenzióval képzett keresztszorzat (Descartes-szorzat) hasznos lehet...
```elixir defmodule T2 do @type elem() :: %{any(), integer()} @spec metszet(am::elem(), bm::elem()) :: cm::elem() # Az am és bm zsákok metszete a cm zsák, azaz a cm kizárólag az am és bm közös elemeit # tartalmazza, mégpedig úgy, hogy cm minden elemének multiplicitása az adott elem # am-beli és bm-beli multiplicitása közül a kisebbik. # Az am és bm zsákok üresek is lehetnek. (11 pont) def metszet(am, bm), do: (_ = am; _ = bm; %{}) end (T2.metszet(%{}, %{}) === %{}) |> IO.inspect() (T2.metszet(%{}, %{111=>10}) === %{}) |> IO.inspect() (T2.metszet(%{11=>10,33=>30}, %{22=>20,44=>40}) === %{}) |> IO.inspect() (T2.metszet(%{11=>10},22=>2},33=>30}, %{11=>1,22=>20}) === %{11=>1,22=>2}) |> IO.inspect() ```
```elixir ``` ```elixir (T2.metszet(%{}, %{}) === %{}) |> IO.inspect() (T2.metszet(%{}, %{111=>10}) === %{}) |> IO.inspect() (T2.metszet(%{11=>10,33=>30}, %{22=>20,44=>40}) === %{}) |> IO.inspect() (T2.metszet(%{11=>10,22=>2,33=>30}, %{11=>1,22=>20}) === %{11=>1,22=>2}) |> IO.inspect() ``` ## 3. feladat: Listakezelés rekurzív függvénnyel: lejtők Egy egészlistában lejtőnek nevezzük a legalább két elemű, egyik irányban sem kiterjeszthető, folytonos, szigorúan monoton csökkenő sorozatokat. Írjon olyan rekurzív függvényt `lejtok` néven az alább definiált `T3.lejto/2` segédfüggvény felhasználásával, amely a paraméterként átadott listából kigyűjti a lejtőket alkotó részlistákat, és ezek listáját adja eredményül, az eredeti sorrend megtartásával. Saját segédfüggvényt definiálhat. __A legalább kételemű listákat mintaillesztéssel ismerje fel, ehhez ne használjon `when` kifejezést őrrel, se a lista hosszát meghatározó bármilyen függvényt, pl. a `length/1`-et. Nem használhatja az `Enum.chunk_by/2`, `Enum.chunk_every/2`, `Enum.chunk_every/4` és `Enum.chunk_while/4` függvényeket sem.__
```elixir defmodule T3 do @spec lejto(xs::[integer()], zs::[z::integer()]) :: {ls::[integer()], rs::[integer()]} # Az [z|xs] egészlista balról az első, lehető leghosszabb, folytonos, # szigorúan monoton csökkenő sorozata ls, maradéka rs def lejto([x|xs], [z|_]=zs) when z > x, do: lejto(xs, [x|zs]) def lejto(xs, zs), do: {Enum.reverse(zs), xs} @spec lejtok(xs::[integer()]) :: rss::[[integer()]] # Az rss az xs-ben előforduló lejtők listája # Lejtőnek nevezzük a legalább két elemű, egyik irányban sem kiterjeszthető, # folytonos, szigorúan monoton csökkenő sorozatot. (10 pont) def lejtok(xs) do _ = xs; nil end end (T3.lejtok([0, 0, 0, 0]) === []) |> IO.inspect() (T3.lejtok([-1, -2, -3, -4]) === [[-1, -2, -3, -4]]) |> IO.inspect() (T3.lejtok([]) === []) |> IO.inspect() (T3.lejtok([5]) === []) |> IO.inspect() (T3.lejtok([5, 4]) === [[5, 4]]) |> IO.inspect() (T3.lejtok([4, 0, 6, 0, 9, 18]) === [[4, 0], [6, 0]]) |> IO.inspect() ```
```elixir ``` ```elixir (T3.lejtok([0, 0, 0, 0]) === []) |> IO.inspect() (T3.lejtok([-1, -2, -3, -4]) === [[-1, -2, -3, -4]]) |> IO.inspect() (T3.lejtok([]) === []) |> IO.inspect() (T3.lejtok([5]) === []) |> IO.inspect() (T3.lejtok([5, 4]) === [[5, 4]]) |> IO.inspect() (T3.lejtok([4, 0, 6, 0, 9, 18]) === [[4, 0], [6, 0]]) |> IO.inspect() ``` ## 4. feladat: Bináris fában lévő számok mediánja Egy bináris fa típusát így definiáljuk: `@type bintree() :: :l | {bintree(), v::any(), bintree()}` Írjon függvényt `median` néven egy bináris fában lévő számok medián (helyzeti közép-)értékének visszaadására! Ha a fában lévő számok száma páros, a két középső érték átlaga legyen az eredmény. Ha a fában nincs szám, a függvény visszatérési értéke `nil` legyen. Segédfüggvényt definiálhat.
```elixir defmodule T4 do @type bintree() :: :l | {bintree(), v :: any(), bintree()} @spec median(t :: bintree()) :: med :: float() | nil # a t fában lévő számok átlaga med (12 pont) def median(t) do _ = t; nil end # Megoldás # def median(t) do # case to_list(t, []) do # [_ | _] = xs -> xs |> Enum.sort() |> calc_med() # [] -> nil # end # end # def calc_med(xs) do # len = length(xs) # idx = div(len,2) # case rem(len,2) do # 1 -> Enum.at(xs, idx) # 0 -> (Enum.at(xs, idx-1) + Enum.at(xs, idx)) / 2 # end # end # def to_list(:l, vs), do: vs # def to_list({lt, v, rt}, vs) do # to_list(lt, to_list(rt, if(is_integer(v), do: [v | vs], else: vs))) # end end t0a = {:l, 8, :l} t0b = {:l, :a, :l} t1a = {{:l, 5, :l}, 6, {:l, 4, :l}} t1b = {{:l, 5, :l}, :a, {:l, 4, :l}} t1c = {{:l, :b, :l}, :a, {:l, :c, :l}} t2a = {{{:l, :a, :l}, 8, {:l, 5, :l}}, 7, {:l, 6, :l}} t2b = {{{:l, 9, :l}, :a, :l}, 3, {:l, 6, :l}} t3a = {{{{{{{:l, 11, :l}, 7, {:l, 12, :l}}, 13, :l}, 9, :l}, 3, :l}, 5, :l}, 4, :l} t3b = {{{{{{{:l, :x, :l}, 7, {:l, 12, :l}}, 13, :l}, 1, :l}, 5, :l}, 4, :l}, :a, :l} (T4.median(t0a) == 8.0) |> IO.inspect() (T4.median(t0b) == nil) |> IO.inspect() (T4.median(t1a) == 5.0) |> IO.inspect() (T4.median(t1b) == 4.5) |> IO.inspect() (T4.median(t1c) == nil) |> IO.inspect() (T4.median(t2a) == 6.5) |> IO.inspect() (T4.median(t2b) == 6.0) |> IO.inspect() (T4.median(t3a) == 8.0) |> IO.inspect() (T4.median(t3b) == 6.0) |> IO.inspect() ```
```elixir ``` ```elixir t0a = {:l, 8, :l} t0b = {:l, :a, :l} t1a = {{:l, 5, :l}, 6, {:l, 4, :l}} t1b = {{:l, 5, :l}, :a, {:l, 4, :l}} t1c = {{:l, :b, :l}, :a, {:l, :c, :l}} t2a = {{{:l, :a, :l}, 8, {:l, 5, :l}}, 7, {:l, 6, :l}} t2b = {{{:l, 9, :l}, :a, :l}, 3, {:l, 6, :l}} t3a = {{{{{{{:l, 11, :l}, 7, {:l, 12, :l}}, 13, :l}, 9, :l}, 3, :l}, 5, :l}, 4, :l} t3b = {{{{{{{:l, :x, :l}, 7, {:l, 12, :l}}, 13, :l}, 1, :l}, 5, :l}, 4, :l}, :a, :l} ``` ```elixir (T4.median(t0a) == 8.0) |> IO.inspect() (T4.median(t0b) == nil) |> IO.inspect() (T4.median(t1a) == 5.0) |> IO.inspect() (T4.median(t1b) == 4.5) |> IO.inspect() (T4.median(t1c) == nil) |> IO.inspect() (T4.median(t2a) == 6.5) |> IO.inspect() (T4.median(t2b) == 6.0) |> IO.inspect() (T4.median(t3a) == 8.0) |> IO.inspect() (T4.median(t3b) == 6.0) |> IO.inspect() ```