defmodule Fpea do @moduledoc """ Példák az FP előadásokhoz @author "phanak@edu.bme.hu" @date "$LastChangedDate: 2024-09-22 14:41:28 +0200 (Sun, 22 Sep 2024) $$" """ # A fájl nevét csupa kisbetűvel kell írni, szóköz helyett aláhúzás-jellel (snake case) # A modul nevét egybe kell írni, a szavakat nagybetűvel kell kezdeni (camel case) @spec fac(n::integer()) :: f::integer() # f = n! (azaz f az n faktoriálisa) def fac(0), do: 1 # ha az n=0 mintaillesztés sikeres def fac(n), do: n * fac(n-1) # ha az n=0 mintaillesztés sikertelen @spec sum(xs::[integer()]) :: s::integer() # Az xs számlista összege s def sum([]), do: 0 def sum(xs) do x = hd(xs); rs = tl(xs); x + sum rs end @spec append(xs::[any()], ys::[any()]) :: rs::[any()] # rs az xs lista ys elé fűzésével kapott lista def append([], ys), do: ys def append(xs, ys), do: [(hd xs) | (append (tl xs), ys)] @spec revapp(xs::[any()], ys::[any()]) :: rs::[any()] # rs a megfordított xs lista ys elé fűzésével kapott lista def revapp([], ys), do: ys def revapp(xs, ys), do: revapp((tl xs), [(hd xs) | ys]) @spec sum_of_squares(a::number(), b::number()) :: s::number() def sum_of_squares(a,b), do: sqr(a) + sqr(b) defp sqr(a), do: a*a # p[rivate], i.e. local in this module def sum_of_sqrs_b5(a, b \\ 5), do: sqr(a) + sqr(b) def sum_of_sqrs_a6b5(a \\ 6, b \\ 5), do: sqr(a) + sqr(b) def head([]), do: {:error, nil} def head([x|_xs]), do: {:ok, x} _tail = fn [] -> {:error, nil}; [_x|xs] -> {:ok, xs} end # cnt_a = fn [] -> 0; [_x|xs] -> (cnt_a xs) + 1 end def cnt_n([]), do: 0; def cnt_n([_x|xs]), do: (cnt_n xs) + 1 def hello_1(msg, name), do: (IO.write msg; IO.puts ", mizújs, #{name}?") def hello_2(msg, name), do: ( # csoportosítás zárójelezéssel IO.write msg # pontosvessző helyett új sorba IO.puts ", mizújs, #{name}?" ) def hello_3(msg, name) do # zárójel helyett do...end IO.write msg IO.puts ", mizújs, #{name}?" end # Már látott megoldás # def fac(0), do: 1 # ha az n=0 mintaillesztés sikeres # def fac(n), do: n * fac(n-1) # ha az n=0 mintaillesztés sikertelen def fac_1(0), do: 1 # ha az n=0 mintaillesztés sikeres def fac_1(n) when n > 0, do: n * fac_1(n-1) # ha az n=0 mintaillesztés sikertelen def fac_2(0), do: 1 # ha az n=0 mintaillesztés sikeres def fac_2(n) when is_integer(n) and n > 0, do: n * fac_2(n-1) # ha az n=0 mintaillesztés sikertelen def filter(_pred, []), do: [] def filter(pred, [x|xs]) do cond do pred.(x) -> [x | filter(pred, xs)] true -> filter(pred, xs) end end @spec freq(val::any(), ls::[any()]) :: n::integer() # ls-ben a val értékű elemek száma n def freq(val, ls), do: (for x <- ls, x === val, do: x) |> length() def freq_r(val, ls), do: (for x <- ls, x === val, reduce: 0, do: (acc -> 1 + acc)) @spec smallers(xs::[integer()]) :: ss::[integer()] # ss azoknak a xs-beli egészeknek a listája, melyek a # közvetlenül előttük álló listaelemnél kisebbek def smallers([_|xs]=xxs) do for {p, c} <- Enum.zip(xxs ,xs), p > c, do: c end def smallers([]), do: [] @spec peaks(xs::[integer()]) :: ps::[integer()] # az xs-beli lokális csúcsok listája ps # egy csúcs lokális, ha mindkét szomszédjánál nagyobb def peaks(xs) do triads = Enum.chunk_every(xs, 3, 1, :discard) for [p, c, n] <- triads, p < c and n < c, do: c end @spec plains(xs::[integer()]) :: ps::[integer()] # az xs lista azonos értékű, maximális hosszúságú, # legalább kételemű sorozatainak, azaz platóinak listája ls def plains(xs) do #plains = Enum.chunk_by(xs, & &1) #plains = Enum.chunk_by(xs, &(&1)) plains = Enum.chunk_by(xs, fn(x) -> x end) for ps = [_,_|_] <- plains, do: ps end @spec pitag1(n::integer()) :: ps::[{integer(),integer(),integer()}] # az n-nél nem nagyobb összegű pitagoraszi számhármasok listája ps def pitag1(n) do ls = 1..n for a <- ls, b <- ls, a <= b, c <- ls, a + b + c <= n, a * a + b * b === c * c, do: {a, b, c} end def pitag2(n) do for a <- 1..n, b <- a..n, c <- b..n, a + b + c <= n, a * a + b * b === c * c, do: {a, b, c} end @spec pitag1cnt(n::integer()) :: cnt::integer() # az n-nél nem nagyobb összegű pitagoraszi számhármasok száma cnt def pitag1cnt(n) do ls = 1..n for a <- ls, b <- ls, a <= b, c <- ls, a + b + c <= n, a * a + b * b === c * c, reduce: 0, do: (acc -> 1 + acc) end def pitag2cnt1(n) do for a <- 1..n, b <- a..n, c <- b..n, a + b + c <= n, a * a + b * b === c * c, reduce: 0, do: (acc -> 1 + acc) end def pitag2cnt2(n) do for a <- 1..n, a2 = a * a, b <- a..n, b2 = b * b, c <- b..n, a + b + c <= n, a2 + b2 === c * c, reduce: 0, do: (acc -> 1 + acc) end def pitag2cnt3(n) do for a <- 1..n, b <- a..n, (ab = a+b) < n, c <- b..n, ab + c <= n, a * a + b * b === c * c, reduce: 0, do: (acc -> 1 + acc) end # Copilot generálta eredeti, zárójelhibás # def count_triples(max_sum) do # for a <- 1..(div(max_sum, 3)), # b <- (a + 1)..(div(max_sum - a, 2)), # c = :math.sqrt(a * a + b * b), # c == trunc(c), # a + b + trunc(c) <= max_sum, # do: {a, b, trunc(c)} # |> Enum.uniq() # |> length() # end # Copilot generálta, zárójelhiba javítva def count_triples(max_sum) do for a <- 1..(div(max_sum, 3)), b <- (a + 1)..(div(max_sum - a, 2)), c = :math.sqrt(a * a + b * b), c == trunc(c), a + b + trunc(c) <= max_sum do {a, b, trunc(c)} end |> Enum.uniq() |> length() end # Copilot generálta, átírva def pitag3cnt1(n) do for a <- 1..(div(n, 3)), b <- (a + 1)..(div(n - a, 2)), c = :math.sqrt(a * a + b * b), c == trunc(c), a + b + c <= n do {a, b, trunc(c)} end |> length() end def pitag3cnt2(n) do for a <- 1..(div(n, 3)), b <- (a + 1)..(div(n - a, 2)), c = :math.sqrt(a * a + b * b), c == trunc(c), a + b + c <= n, reduce: 0, do: (acc -> 1 + acc) end def pitag3cnt3(n) do for a <- 1..(div(n, 3)), b <- (a + 1)..(div(n - a, 2)), c = :math.sqrt(a * a + b * b), c == trunc(c), a + b + c <= n do :any_atom end |> length() end # Benchee.run( # %{ # "pitag1cnt: naiv" => fn -> 200 |> Fpea.pitag1cnt() end, # "pitag2cnt1: b>=a,c>=b" => fn -> 200 |> Fpea.pitag2cnt1() end, # "pitag2cnt2: 2cnt1 + a2,b2" => fn -> 200 |> Fpea.pitag2cnt2() end, # "pitag2cnt3: 2cnt1 + a+b fn -> 200 |> Fpea.pitag2cnt3() end, # "pitag3cnt1: szamolt c + {}-lista" => fn -> 200 |> Fpea.pitag3cnt1() end, # "pitag3cnt2: 3cnt1 + reduce" => fn -> 200 |> Fpea.pitag3cnt2() end, # "pitag3cnt3: 3cnt1 + atomlista" => fn -> 200 |> Fpea.pitag3cnt3() end # }# , profile_after: true # ) def pitag_test() do 800 |> Fpea.pitag1cnt() |> IO.inspect(label: "pitag1cnt ") 800 |> Fpea.pitag2cnt1() |> IO.inspect(label: "pitag2cnt1") 800 |> Fpea.pitag2cnt2() |> IO.inspect(label: "pitag2cnt2") 800 |> Fpea.pitag2cnt3() |> IO.inspect(label: "pitag2cnt3") 800 |> Fpea.pitag3cnt1() |> IO.inspect(label: "pitag3cnt1") 800 |> Fpea.pitag3cnt2() |> IO.inspect(label: "pitag3cnt2") 800 |> Fpea.pitag3cnt3() |> IO.inspect(label: "pitag3cnt3") end def qsort([]), do: [] def qsort([pivot|tail]), do: qsort(for x <- tail, x < pivot, do: x) ++ [ pivot | qsort(for x <- tail, x >= pivot, do: x) ] @spec perms(xs::[any()]) :: pss::[[any()]] # Az xs lista elemeinek összes permutációját tartalmazó lista pss def perms([]), do: [[]] def perms(xs), do: (for y <- xs, ys <- perms(xs--[y]), do: [y|ys]) @type asciicode() :: integer() @spec to_decval_cond(hexval::asciicode()) :: d::integer() def to_decval_cond(hexval) do cond do ?0 <= hexval && hexval <= ?9 -> hexval - ?0 ?a <= hexval and hexval <= ?f -> hexval - ?a + 10 end end def to_decval_cond2(hexval) do cond do ?0 <= hexval and hexval <= ?9 -> hexval - ?0 ?a <= hexval and hexval <= ?f -> hexval - ?a + 10 true -> nil end end def to_decval_cond3(hexval) do cond do ?0 <= hexval && hexval <= ?9 -> {:ok, hexval - ?0} ?a <= hexval && hexval <= ?f -> {:ok, hexval - ?a + 10} true -> :error end end @spec to_decval_case(hexval::asciicode()) :: d::integer() def to_decval_case(hexval) do case hexval do hv when ?0 <= hv and hv <= ?9 -> hv - ?0 ?a -> 10 ?b -> 11 ?c -> 12 ?d -> 13 ?e -> 14 ?f -> 15 _ -> nil end end def to_decval_case2(hexval), do: (case hexval do _ when ?0 <= hexval and hexval <= ?9 -> hexval - ?0 _ when ?a <= hexval and hexval <= ?f -> hexval - ?a + 10 _ -> nil end) def guess_case(val) do integer? = fn(v when is_integer(v)) -> {v, :ok}; _ -> :non_int end positive? = fn(v when v > 0) -> {v, :ok}; _ -> :non_pos end in_range? = fn(v when 6 <=v and v <= 18) -> {v, :ok}; _ -> :out end case integer?.(val) do {v, :ok} -> case positive?.(v) do {v, :ok} -> case in_range?.(v) do {v, :ok} -> IO.puts("#{v}: bingó!") :out -> IO.puts("#{v}: out of range.") end :non_pos -> IO.puts("#{v}: wrong number.") end :non_int -> IO.puts("#{val}: wrong value.") end end def guess_with(val) do integer? = fn(v when is_integer(v)) -> {v, :ok}; _ -> :non_int end positive? = fn(v when v > 0) -> {v, :ok}; _ -> :non_pos end in_range? = fn(v when 6 <=v and v <= 18) -> {v, :ok}; _ -> :out end with {v, :ok} <- integer?.(val), {v, :ok} <- positive?.(v), {v, :ok} <- in_range?.(v) do IO.puts("#{v}: bingó!") else :non_int -> IO.puts("#{val}: wrong value.") :non_pos -> IO.puts("#{val}: wrong number.") :out -> IO.puts("#{val}: out of range.") end end end