# Run as: iex --dot-iex dp24a-fp3gy-megoldas.exs # Title: DP24a - 3. FP gyakorlat, 2024-09-23 # ── Műveletek listákon ── # ### Lista kettévágása defmodule Split1 do @spec split(xs :: [any()], n :: integer()) :: {ps :: [any()], ss :: [any()]} # Az xs lista n hosszú prefixuma (első n eleme) ps, length(xs)-n # hosszú szuffixuma (első n eleme utáni része) pedig ss def split([], _n), do: {[], []} def split(xs, 0), do: {[], xs} def split([x | xs], n) do {ps, ss} = split(xs, n - 1) {[x | ps], ss} end end IO.puts(Split1.split([10, 20, 30, 40, 50], 3) === {[10, 20, 30], [40, 50]}) IO.puts(IO.inspect(Split1.split(~c"egyedem-begyedem", 8)) === Enum.split(~c"egyedem-begyedem", 8)) IO.puts(IO.inspect(Split1.split(~c"papás-mamás", 6)) === Enum.split(~c"papás-mamás", 6)) IO.puts(Split1.split(~c"nem_vágom", 0) === Enum.split(~c"nem_vágom", 0)) IO.puts(Split1.split(~c"", 10) === Enum.split(~c"", 10)) IO.puts(Split1.split(~c"", 0) === Enum.split(~c"", 0)) defmodule Split2 do @spec split(xs :: [any()], n :: integer()) :: {ps :: [any()], ss :: [any()]} # Az xs lista n hosszú prefixuma (első n eleme) ps, length(xs)-n # hosszú szuffixuma (első n eleme utáni része) pedig ss def split(xs, n), do: split(xs, n, []) @spec split(xs :: [any()], n :: integer(), zs :: integer()) :: {ps :: [any()], ss :: [any()]} # Az xs lista n hosszú prefixuma ps, első n eleme utáni szuffixuma ss # zs a prefixumot gyűjtő akkumulátor def split([], _n, zs), do: {rev(zs), []} def split(xs, 0, zs), do: {rev(zs), xs} def split([x | xs], n, zs), do: split(xs, n - 1, [x | zs]) @spec rev(xs :: [any()]) :: rs :: [any()] # xs megfordítottja rs def rev(xs), do: rev(xs, []) @spec rev(xs :: [any()], zs :: [any()]) :: rs :: [any()] def rev([x | xs], zs), do: rev(xs, [x | zs]) def rev([], zs), do: zs end IO.puts(Split2.split([10, 20, 30, 40, 50], 3) === {[10, 20, 30], [40, 50]}) IO.puts(IO.inspect(Split2.split(~c"egyedem-begyedem", 8)) === Enum.split(~c"egyedem-begyedem", 8)) IO.puts(IO.inspect(Split2.split(~c"papás-mamás", 6)) === Enum.split(~c"papás-mamás", 6)) IO.puts(Split2.split(~c"nem_vágom", 0) === Enum.split(~c"nem_vágom", 0)) IO.puts(Split2.split(~c"", 10) === Enum.split(~c"", 10)) IO.puts(Split2.split(~c"", 0) === Enum.split(~c"", 0)) # ### Lista adott feltételt kielégítő elemeiből álló prefixuma defmodule Take1 do @spec takewhile(xs :: [any()], f :: (any() -> boolean())) :: rs :: [any()] def takewhile([], _f), do: [] def takewhile([x | xs], f) do cond do f.(x) -> [x | takewhile(xs, f)] true -> [] end end end IO.puts(Take1.takewhile(~c"álom12" ++ [:a] ++ [~c"34brigád"], &is_integer/1) === ~c"álom12") IO.puts(Take1.takewhile(~c"abcdefghijkl", fn x -> x < ?f end) === ~c"abcde") defmodule Take2 do @spec takewhile(xs :: [any()], f :: (any() -> boolean())) :: rs :: [any()] def takewhile(xs, f), do: Split2.rev(takewhile(xs, f, [])) @spec takewhile(xs :: [any()], f :: (any() -> boolean()), zs :: [any()]) :: rs :: [any()] def takewhile([], _f, zs), do: zs def takewhile([x | xs], f, zs) do cond do f.(x) -> takewhile(xs, f, [x | zs]) true -> zs end end end IO.puts(Take2.takewhile(~c"álom12" ++ [:a] ++ [~c"34brigád"], &is_integer/1) === ~c"álom12") IO.puts(Take2.takewhile(~c"abcdefghijkl", fn x -> x < ?f end) === ~c"abcde") # ### Lista minden n-edik elemének kihagyásával létrejövő lista defmodule Drop1 do @spec dropevery(xs :: [any()], n :: integer()) :: rs :: [any()] def dropevery([], _n), do: [] def dropevery(xs, n) do for i <- 1..length(xs), rem(i, n) != 1, do: Enum.at(xs, i - 1) end end ls = ~c"álom" ++ [:a] ++ ~c"egybrigád" IO.inspect(Drop1.dropevery(ls, 4) === ~c"lomegyrigd") ls = ~c"abcdefghijkl" IO.inspect(Drop1.dropevery(ls, 5) === ~c"bcdeghijl") ls = ~c"1234567" IO.inspect(Drop1.dropevery(ls, 2) === ~c"246") ls = [] IO.inspect(Drop1.dropevery(ls, 3) === []) ls = [:a, :b, :c, :d, :e, :f, :g, :h, :i, :j, :k, :l, :m] IO.inspect(Drop1.dropevery(ls, 3) === [:b, :c, :e, :f, :h, :i, :k, :l]) defmodule Drop2 do @spec dropevery(xs :: [any()], n :: integer()) :: rs :: [any()] def dropevery(xs, n), do: Split2.rev(dropevery(xs, n, 1, [])) def dropevery([], _n, _i, zs), do: zs def dropevery([x | xs], n, i, zs) when rem(i, n) != 1, do: dropevery(xs, n, i + 1, [x | zs]) def dropevery([_ | xs], n, i, zs), do: dropevery(xs, n, i + 1, zs) end ls = ~c"álom12" ++ [:a] ++ [~c"34brigád"] IO.puts(Drop2.dropevery(ls, 5) == Enum.drop_every(ls, 5)) ls = ~c"abcdefghijkl" IO.inspect(Drop2.dropevery(ls, 4)) ls = ~c"1234567" IO.inspect(Drop2.dropevery(ls, 2)) ls = [] IO.inspect(Drop2.dropevery(ls, 3)) ls = [:a, :b, :c, :d, :e, :f, :g, :h, :i, :j, :k, :l, :m] IO.inspect(Drop2.dropevery(ls, 3)) # ### Lista egyre rövidülő szuffixumainak listája defmodule Tails do @spec tails(xs :: [any]) :: zss :: [[any]] # Az xs lista egyre rövidülő szuffixumainak listája zss def tails([]), do: [[]] def tails([_x | xs] = xxs), do: [xxs | tails(xs)] end IO.puts(Tails.tails([1, 4, 2]) === [[1, 4, 2], [4, 2], [2], []]) IO.puts(Tails.tails([:a, :b, :c, :d]) === [[:a, :b, :c, :d], [:b, :c, :d], [:c, :d], [:d], []]) IO.puts(Tails.tails([:z]) === [[:z], []]) IO.puts(Tails.tails([]) === [[]]) # ### Lista egymást követő két-két eleméből képzett párok listája defmodule Pairs do @spec pairs(xs :: [any()]) :: zs :: [any()] def pairs([x1, x2 | xs]), do: [{x1, x2} | pairs(xs)] def pairs(_), do: [] end zs = [{1, 2}, {3, 4}, {5, 6}, {7, 8}, {9, 10}, {11, 12}, {13, 14}, {15, 16}, {17, 18}, {19, 20}] (1..20 |> Range.to_list() |> Pairs.pairs() == zs) |> IO.puts() zs = [{1, 2}, {3, 4}, {5, 6}, {7, 8}, {9, 10}] (1..11 |> Range.to_list() |> Pairs.pairs() == zs) |> IO.puts() ([1] |> Pairs.pairs() == []) |> IO.puts() ([1] |> Pairs.pairs() == []) |> IO.puts() # ### Listában párosával előforduló elemek listája defmodule Parosan1 do @spec parosan(xs :: [any()]) :: rs :: [any()] # Az xs lista összes olyan elemének listája rs, amely # után vele azonos értékű elem áll def parosan([x | [x | _xs] = xxs]), do: [x | parosan(xxs)] def parosan([_ | [_x | _xs] = xxs]), do: parosan(xxs) def parosan(_), do: [] end IO.puts(Parosan1.parosan([:a, :a, :a, 2, 3, 3, :a, 2, :b, :b, 4, 4]) === [:a, :a, 3, :b, 4]) IO.puts(Parosan1.parosan([:a, 2, 3, :a, 2, :b, 4]) === []) IO.puts(Parosan1.parosan([:a]) === []) IO.puts(Parosan1.parosan([]) === []) defmodule Parosan2 do @spec parosan(xs :: [any()]) :: rs :: [any()] # Az xs lista összes olyan elemének listája rs, amely # után vele azonos értékű elem áll def parosan(xs), do: parosan(xs, []) |> Split2.rev() @spec parosan(xs :: [any()], zs :: [any()]) :: rs :: [any()] def parosan([x | [x | _xs] = xxs], zs), do: parosan(xxs, [x | zs]) def parosan([_ | [_x | _xs] = xxs], zs), do: parosan(xxs, zs) def parosan(_, zs), do: zs end IO.puts(Parosan2.parosan([:a, :a, :a, 2, 3, 3, :a, 2, :b, :b, 4, 4]) === [:a, :a, 3, :b, 4]) IO.puts(Parosan2.parosan([:a, 2, 3, :a, 2, :b, 4]) === []) IO.puts(Parosan2.parosan([:a]) === []) IO.puts(Parosan2.parosan([]) === []) defmodule Parosan3 do @spec parosan(xs :: [any()]) :: rs :: [any()] # Az xs lista összes olyan elemének listája rs, amely # után vele azonos értékű elem áll def parosan([]), do: [] def parosan(xs) do for {x, y} <- Enum.zip(xs, tl(xs)), x === y, do: x end end IO.puts(Parosan3.parosan([:a, :a, :a, 2, 3, 3, :a, 2, :b, :b, 4, 4]) === [:a, :a, 3, :b, 4]) IO.puts(Parosan3.parosan([:a, 2, 3, :a, 2, :b, 4]) === []) IO.puts(Parosan3.parosan([:a]) === []) IO.puts(Parosan3.parosan([]) === []) # ### Listában kulcs-érték párokban előforduló értékek listája defmodule Ertekek1 do @spec ertekek(xs :: [any()]) :: vs :: [any()] # Az xs lista elemei közül a {:v::atom(), v::any()} mintára illeszkedő # párok 2. tagjából képzett lista vs def ertekek([]), do: [] def ertekek([{:v, v} | xs]), do: [v | ertekek(xs)] def ertekek([_ | xs]), do: ertekek(xs) end Ertekek1.ertekek([:alma, {:s, 3}, {:v, 1}, 3, {:v, 2}]) === [1, 2] defmodule Ertekek2 do @spec ertekek(xs :: [any()]) :: vs :: [any()] # Az xs lista elemei közül a {:v::atom(), v::any()} mintára illeszkedő # párok 2. tagjából képzett lista vs def ertekek(xs), do: ertekek(xs, []) |> Split2.rev() @spec ertekek(xs :: [any()], zs :: [any()]) :: vs :: [any()] def ertekek([], zs), do: zs def ertekek([{:v, v} | xs], zs), do: ertekek(xs, [v | zs]) def ertekek([_ | xs], zs), do: ertekek(xs, zs) end Ertekek2.ertekek([:alma, {:s, 3}, {:v, 1}, 3, {:v, 2}]) === [1, 2] defmodule Ertekek3 do @spec ertekek(xs :: [any()]) :: vs :: [any()] # Az xs lista elemei közül a {:v::atom(), v::any()} mintára illeszkedő # párok 2. tagjából képzett lista vs def ertekek(xs) do Enum.filter(xs, fn {:v, _} -> true _ -> false end) |> Enum.map(fn {:v, v} -> v end) end end Ertekek3.ertekek([:alma, {:s, 3}, {:v, 1}, 3, {:v, 2}]) === [1, 2] defmodule Ertekek4 do @spec ertekek(xs :: [any()]) :: vs :: [any()] # Az xs lista elemei közül a {:v::atom(), v::any()} mintára illeszkedő # párok 2. tagjából képzett lista vs def ertekek(xs), do: for({:v, v} <- xs, do: v) end Ertekek4.ertekek([:alma, {:s, 3}, {:v, 1}, 3, {:v, 2}]) === [1, 2] # ### Lista elején azonos értékű elemekből álló részlisták listája defmodule Repeated1 do @spec repeated(xs :: [any()]) :: rs :: [any()] def repeated([]), do: [] def repeated(xs), do: repeated(xs, 1) def repeated(xs, i) do cond do Enum.take(xs, i) == Enum.drop(xs, i) |> Enum.take(i) -> [Enum.take(xs, i) | repeated(xs, i + 1)] true -> [] end end end IO.inspect(Repeated1.repeated([:a, :a, :a, 2, 3, 3, :a, :b, :b, :b, :b]) === [[:a]]) IO.inspect(Repeated1.repeated([:a, :b, :b, :b, :b]) === []) IO.inspect(Repeated1.repeated([:b, :b, :b, :b]) === [[:b], [:b, :b]]) IO.inspect(Repeated1.repeated([]) === []) defmodule Repeated2 do @spec repeated(xs :: [any()]) :: rs :: [any()] def repeated([]), do: [] def repeated(xs), do: repeated(xs, 1, []) def repeated(xs, i, zs) do cond do Enum.take(xs, i) == Enum.drop(xs, i) |> Enum.take(i) -> repeated(xs, i + 1, [Enum.take(xs, i) | zs]) true -> Enum.reverse(zs) end end end IO.inspect(Repeated2.repeated([:a, :a, :a, 2, 3, 3, :a, :b, :b, :b, :b]) === [[:a]]) IO.inspect(Repeated2.repeated([:a, :b, :b, :b, :b]) === []) IO.inspect(Repeated2.repeated([:b, :b, :b, :b]) === [[:b], [:b, :b]]) IO.inspect(Repeated2.repeated([]) === []) # ### Listában párosával előforduló részlisták listája defmodule Stammering1 do @spec stammering(xs :: [any()]) :: zss :: [[any()]] # zss az xs lista összes olyan nemüres, folytonos részlistájából # álló lista, amelyet vele azonos értékű részlista követ def stammering(xs) do for zs <- Tails.tails(xs) do # IO.inspect(zs) Repeated1.repeated(zs) end |> Enum.concat() end end (Stammering1.stammering([:a, :a, :a, 2, 3, 3, :a, :b, :b, :b, :b]) === [[:a], [:a], [3], [:b], [:b, :b], [:b], [:b]]) |> IO.puts() IO.puts(Stammering1.stammering([]) === []) IO.puts(Stammering1.stammering([:a]) === []) IO.puts(Stammering1.stammering([:a, :a]) === [[:a]]) IO.puts(Stammering1.stammering([:a, :b]) === []) # ### Természetes szám valódi osztói proper_divisors = &for j <- 2..div(&1, 2), rem(&1, j) === 0, do: j (proper_divisors.(10) === [2, 5]) |> IO.inspect(charlists: :as_list) (proper_divisors.(23) === []) |> IO.inspect(charlists: :as_list) (proper_divisors.(48) === [2, 3, 4, 6, 8, 12, 16, 24]) |> IO.inspect(charlists: :as_list) (proper_divisors.(128) === [2, 4, 8, 16, 32, 64]) |> IO.inspect(charlists: :as_list) # ### Összetett számok composite_numbers = &for j <- 4..&1, length(proper_divisors.(j)) > 0, do: j (composite_numbers.(11) === [4, 6, 8, 9, 10]) |> IO.inspect(charlists: :as_list) (composite_numbers.(17) === [4, 6, 8, 9, 10, 12, 14, 15, 16]) |> IO.inspect(charlists: :as_list) # #### Hatékonyabb megoldás probes = &[2 | Enum.to_list(3..floor(:math.sqrt(&1))//2)] composite? = &Enum.reduce(probes.(&1), false, fn x, y -> rem(&1, x) == 0 or y end) composite_numbers_faster = &for i <- 4..&1, composite?.(i), do: i (composite_numbers_faster.(11) === [4, 6, 8, 9, 10]) |> IO.inspect(charlists: :as_list) (composite_numbers_faster.(21) === [4, 6, 8, 9, 10, 12, 14, 15, 16, 18, 20, 21]) |> IO.inspect(charlists: :as_list)