# $LastChangedDate: 2024-10-25 13:54:47 +0200 (Fri, 25 Oct 2024) $ # exec_dummy: if true, exec dummy, else exec solution exec_dummy = true #--- 1. feladat: Egyklózos névtelen függvények # @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. f1 = if exec_dummy do fn(xs) -> _ = xs; nil end else # Megoldás fn(xs) -> for {x,i} <- Enum.zip(xs, 0..(length(xs)-1)), rem(i, 3) != 0, do: x end end (f1.([1,-4,5,6,"5",-3,12,11,7,4]) === [-4,5,"5",-3,11,7]) |> IO.inspect() (f1.([:a,4]) === [4]) |> IO.inspect() (f1.([:b]) === []) |> IO.inspect() (f1.([0,:c,-1]) === [:c,-1]) |> IO.inspect() (f1.([]) === []) |> IO.inspect() # @spec f2(coll :: [integer()] | Range.t()) :: s :: integer() # A coll számlista vagy tartomány páros értékű elemeinek összege s f2 = if exec_dummy do fn(coll) -> _ = coll; nil end else # Megoldás: fn(coll) -> for x <- coll, rem(x,2)==0, reduce: 0, do: (acc -> x+acc) end end (f2.(1..10) === 30) |> IO. inspect() (f2.(10..1 // -3) === 14) |> IO. inspect() (f2.([-7, -4, -2, -1, 0, 4, 9, 12, 14, 17, 26]) === 50) |> IO. inspect() # @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. Javasoljuk az Enum.zip/2 és # Enum.split_while/2 függvények használatát. f3 = if exec_dummy do fn(xs) -> _ = xs; nil end else # Megoldás fn(xs) -> (Enum.split_while(Enum.zip(xs, tl(xs)), fn{x,y} -> x <= y end) |> elem(0) |> length()) + 1 end end (f3.([6]) === 1) |> IO.inspect() (f3.([6, 7, 8, 6, 7, 8, 6, 7, 9]) === 3) |> IO.inspect() (f3.([2, 2, 2, 3, 3, 3]) === 6) |> IO.inspect() (f3.([-1, -2, -2]) === 1) |> IO.inspect() (f3.([3, 2, 1, 0]) === 1) |> IO.inspect() (f3.([1, 2, 3, 4, 5, 6, 7]) === 7) |> IO.inspect() #--- 2. feladat: Műveletvégzés bináris fa levelein # Egy bináris fa típusát így definiáljuk: # @type bintree() :: :l | {v::any(), bintree(), bintree()} # Írjon olyan rekurzív függvényt plainmap néven, amelynek két paramétere van: # az első egy bináris fa, a második a fa összes csompontjában lévő v értékre # alkalmazandó függvény. A plainmap/2 eredménye a transzformált fa legyen. # Írja meg a plainmap olyan egyparaméteres változatait is a megfelelő névtelen # segédfüggvény definiálásával, amelyeknek az alábbi példákban látható az # eredménye (az fn() -> nil end-et cserélje le egy megfelelő függvényre). A # segédfüggvény teszőleges könyvtári függvény, itt definiált névtelen függvény # vagy a kettő kombinációja lehet. defmodule T2 do @type bintree() :: :l | {v :: any(), bintree(), bintree()} @spec plainmap(bt :: bintree(), f :: (any() -> any())) :: rt :: bintree() # rt a bt olyan másolata, melyben minden bt-beli v érték helyett az f(v) érték van if exec_dummy do def plainmap(bt, f) do _ = {bt, f}; nil end # Minden v érték azonos az eredetivel def map_identical(bt), do: plainmap(bt, fn() -> nil end) # Minden v érték true, ha az eredeti integer() típusú érték páratlan, egyébként false def map_parity(bt), do: plainmap(bt, fn() -> nil end) # Minden v érték az eredeti String.t() típusú érték zárójelbe téve def map_enclose(bt), do: plainmap(bt, fn() -> nil end) # Minden v érték [] lesz, ha az eredeti érték %{} volt def map_replace_map(bt), do: plainmap(bt, fn() -> nil end) else def plainmap(:l, _f), do: :l def plainmap({v, lt, rt}, f), do: {f.(v), plainmap(lt, f), plainmap(rt, f)} # Minden v érték azonos az eredetivel def map_identical(bt), do: plainmap(bt, & &1) # Minden v érték true, ha az eredeti integer() típusú érték páratlan, egyébként false def map_parity(bt), do: plainmap(bt, fn x -> rem(x, 2) == 1 end) # Minden v érték az eredeti String.t() típusú érték zárójelbe téve def map_enclose(bt), do: plainmap(bt, &("(" <> &1 <> ")")) # Minden v érték [] lesz, ha az eredeti érték %{} volt def map_replace_map(bt), do: plainmap(bt, fn %{} -> []; v -> v end) end end t1 = {:a,{:b,{:d,:l,:l},{:e,:l,:l}},{:c,{:f,:l,:l},:l}} t2 = {3,{6,{2,:l,:l},{4,:l,:l}},{5,{8,:l,:l},:l}} t3 = {6,{5,{3,{1,:l,:l},:l},{7,:l,:l}},:l} t4 = {"itt",{"ott",{"pint",{"pont",:l,:l},:l},{"pánt",:l,:l}},:l} t5 = {:a,{:b,{%{},:l,:l},{:e,:l,:l}},{%{},{:f,:l,:l},:l}} (T2.map_identical(t1) === {:a, {:b, {:d, :l, :l}, {:e, :l, :l}}, {:c, {:f, :l, :l}, :l}}) |> IO.inspect() (T2.map_identical(t2) === {3, {6, {2, :l, :l}, {4, :l, :l}}, {5, {8, :l, :l}, :l}}) |> IO.inspect() (T2.map_parity(t2) === {true, {false, {false, :l, :l}, {false, :l, :l}}, {true, {false, :l, :l}, :l}}) |> IO.inspect() (T2.map_parity(t3) === {false, {true, {true, {true, :l, :l}, :l}, {true, :l, :l}}, :l}) |> IO.inspect() (T2.map_enclose(t4) === {"(itt)", {"(ott)", {"(pint)", {"(pont)", :l, :l}, :l}, {"(pánt)", :l, :l}}, :l}) |> IO.inspect() (T2.map_replace_map(t5) === {:a, {:b, {[], :l, :l}, {:e, :l, :l}}, {[], {:f, :l, :l}, :l}}) |> IO.inspect() #--- 3. feladat: Listakezelés rekurzív függvénnyel # 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 # függvényt slopes néven, ami 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. Használhatja a T3.slope/2 segédfüggvényt. Javasoljuk, # hogy a legalább kételemű listákat mintaillesztéssel ismerje fel, ne # használjon when kifejezést őrrel, se a lista hosszát meghatározó bármilyen # függvényt, pl. a length/1-et. Segédfüggvényt definiálhat. defmodule T3 do @spec slope(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 slope([x|xs], [z|_]=zs) when z > x, do: slope(xs, [x|zs]) def slope(xs, zs), do: {Enum.reverse(zs), xs} @spec slopes(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. if exec_dummy do def slopes(xs) do _ = xs; nil end else def slopes([x | xs]) do {ls, rs} = slope(xs, [x]) case ls do [_, _ | _] -> [ls | slopes(rs)] _ -> slopes(rs) end end def slopes([]), do: [] end end (T3.slope([2, 1, -1, -1, 4, 4, -2, 5, 0, 6, 7, 8, 9], [3]) === {[3, 2, 1, -1], [-1, 4, 4, -2, 5, 0, 6, 7, 8, 9]}) |> IO.inspect() (T3.slopes([1, 2, 3, -1, -1, 4, 4, -2, 5, 0, 6, 7, 8, 9]) === [[3, -1], [4, -2], [5, 0]]) |> IO.inspect() (T3.slopes(~c"dcba" ++ Range.to_list(100..97//-1) ++ [0, 0, 0] ++ ~c"yyy") === [[?d, ?c, ?b, ?a], [100, 99, 98, 97, 0]]) |> IO.inspect() (T3.slopes([0, 0, 0, 0]) === []) |> IO.inspect() (T3.slopes([-1, -2, -3, -4]) === [[-1, -2, -3, -4]]) |> IO.inspect() (T3.slopes([]) === []) |> IO.inspect() (T3.slopes([5]) === []) |> IO.inspect() (T3.slopes([5, 4]) === [[5, 4]]) |> IO.inspect() (T3.slopes([4, 0, 6, 0, 9, 18]) === [[4, 0], [6, 0]]) |> IO.inspect() #--- 4. 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. 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 if exec_dummy do def median(t) do _ = t; nil end else 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 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()