Check if all elements in list have a :ok element - functional-programming

I have one list of tuples like this
[
{:ok, {"0000 0000 "}},
{:ok, %{AM01: %{"C4" => "1111", "C5" => "1"}}},
{:ok, %{AM04: %{"C2" => "2222", "C6" => "2"}}}
]
The first element of tuple :ok represents the map ok.
How ca n I reduce this list to one list like this
[:ok, :ok, :ok]
because after this transformation I will check if all ok with Enum.all?

#JustinWood had demonstrated the most idiomatic erlang approach.
The most idiomatic elixir approach would be probably to use Kernel.match?/2, which is basically a syntactic sugar for two true/false clauses:
Enum.all?(input, &match?({:ok, _}, &1))
#⇒ true
Getting all :ok is usually done with Kernel.SpecialForms.for/1 list comprehension, which filters and maps in one loop:
for {:ok, _} <- input, do: :ok
#⇒ [:ok, :ok, :ok]

Instead of iterating through the list to convert to a list of atoms, you can just use Enum.all?/2 immediately.
result = [
{:ok, {"0000 0000 "}},
{:ok, %{AM01: %{"C4" => "1111", "C5" => "1"}}},
{:ok, %{AM04: %{"C2" => "2222", "C6" => "2"}}}
]
Enum.all?(result, fn
{:ok, _} -> true
_ -> false
end)

Using elem/2, you can reduce the map like this:
Enum.map(foo, &elem(&1, 0))
> [:ok, :ok, :ok]
Or just use all? directly:
Enum.all?(foo, &elem(&1, 0) == :ok)
> true

Another option:
def check_ok([]), do: true
def check_ok([{:ok, _} | tail]), do: check_ok(tail)
def check_ok(_), do: false
As long as :ok is found in each element of the list, the empty list will eventually match(clause #1) and return true. Otherwise, when something other than :ok is found, the recursion will end immediately and the function will return false(clause #3).

Related

Get all keys from nested map

I did this task using iteraptor libary, how can i do it using only elixir fuctionc not external libraries for example using get_in/2
defmodule MapanalizTest do
use ExUnit.Case
doctest Mapanaliz
test "all_path_list(prev_result, xmap, prev_path)" do
assert Mapanaliz.all_path_list(%{}, []) == []
assert Mapanaliz.all_path_list(%{a1: 1}, []) == [[:a1]]
assert Mapanaliz.all_path_list(%{a1: 1, a2: 1}, []) == [[:a1], [:a2]]
assert Mapanaliz.all_path_list(%{a1: %{b1: 1}}, []) == [[:a1], [:a1, :b1]]
assert Mapanaliz.all_path_list(%{a1: 1, a2: %{b1: 1}}) == [[:a1], [:a2], [:a2, :b1]]
assert Mapanaliz.all_path_list(%{a1: 1, a2: %{a2b1: 1, a2b2: 1}}) ==
[[:a1], [:a2], [:a2, :a2b1], [:a2, :a2b2]]
assert Mapanaliz.all_path_list(%{a: %{c: 1, d: 1}, b: %{e: 1}}) ==
[[:a], [:b], [:a, :c], [:a, :d], [:b, :e]]
assert Mapanaliz.all_path_list(%{z1: %{y11: 1, y12: 1}, z2: %{y21: %{x221: 1}}}) ==
[[:z1], [:z2], [:z1, :y11], [:z1, :y12], [:z2, :y21], [:z2, :y21, :x221]]
end
end
SOLUTION I did it like that using Iteraptor module, but how can i do that using only buildin functions
defmodule Mapanaliz do
def all_path_list(xmap) do
case xmap do
%{} -> []
end
xmap
|> Iteraptor.reduce([], fn {k, _}, acc ->
[Enum.join(k, ", ") | acc]
end, yield: :all)
|> :lists.reverse()
end
Rather than a built-in function, this is typically a case for recursion since you want to iterate on a tree:
defmodule Mapanaliz do
def all_path_list(map, path \\ []) do
Enum.flat_map(map, fn {key, value} ->
new_path = path ++ [key]
children = if is_map(value), do: all_path_list(value, new_path), else: []
[new_path | children]
end)
end
end
Explanation:
we "loop" on the map keys and values
if the value is not a map, we just add the current path
if the value is a map, we get all its children paths by making a recursive call to all_path_list
There are probably many ways to implement this using recursion.
Here I went with Enum.flat_map/2 because we want to merge all paths in a single list, not a list of lists.
But you can probably make it more efficient by passing a list accumulator and reversing the list at the end.

Elixir: recursive generators

Is it possible to build a Python style recursive generator with Elixir? Something like this:
def traverse(parent_dir):
dirs, files = get_dirs_and_files_as_lists(parent_dir)
for d in dirs:
yield from traverse(d)
for f in files:
yield f
For all the files to be processed linearly, without overhead implied by an eager list of indefinite length:
for f in traverse(dir):
process(f)
This, or some working equivalent, should be possible using streams; unfortunately, I have no idea how.
I want something like this, just lazy:
def traverse_eagerly(parent_dir) do
{dirs, files} = get_dirs_and_files_as_lists(parent_dir)
for x <- dirs do
traverse_eagerly(x)
end
|> Enum.concat()
|> Enum.concat(files)
end
The solution appears to be trivial: replace Enum with Stream.
def traverse_lazily(parent_dir) do
{dirs, files} = get_dirs_and_files_as_lists(parent_dir)
for x <- dirs do
traverse_lazily(x)
end
|> Stream.concat()
|> Stream.concat(files)
end
The following works as expected:
s = traverse_lazily(a_dir_of_choice)
for x <- s, do: whatever_you_please(x)
Very nice of the language. As fine a solution as you would wish for. Unless I'm missing something, that is :) . Comments are welcome!
You do not need Stream here, but if you want, here is it:
defmodule Traverse do
#spec traverse(root :: binary(), yielder :: (binary() -> any())) ::
:ok | {:error, posix()}
def traverse(root, yielder) do
# https://hexdocs.pm/elixir/master/File.html?#ls/1
with {:ok, list} <- File.ls(root) do
list
|> Stream.each(fn file_or_dir ->
if File.dir?(file_or_dir),
do: traverse(file_or_dir, yielder), # TCO
else: yielder.(file_or_dir)
end)
|> Stream.run()
end
end
end
And call it like:
Traverse.traverse(".", &IO.inspect/1)

Enumerating an Elixir HashDict structure

I'm a newbie to Elixir and am trying to write a GenServer that stores key, value pairs in a HashDict. Storing a compound key and value is fine. here's the code:
#Initialise the HashDict GenServer.start_link
def init(:ok) do
{:ok, HashDict.new}
end
#Implement the server call back for GenServer.cast
def handle_cast({:add, event}, dict) do
{foo, bar, baz, qux} = event
key = %{key1: foo, key2: bar}
value = %{val1: baz, val2: qux}
{:noreply, HashDict.put(dict, key, value) }
end
All good. But I'm having trouble implementing the handle_call behaviour that I want. So here I'd like:
For a given key1 value, retrieve all corresponding value entries in HashDict. This will mean ignoring the value for key2 (so kind of a select all).
Having returned all the val2s, add them all up (assuming they are integers, ignoring val1) to give an overall sum.
So I've got this far:
def handle_call({:get, getKey}, _from, dict) do
key = %{key1: getKey, key2: _}
{:reply, HashDict.fetch(dict, key), dict}
end
This doesn't work, as it's not possible to pattern match on _. Presumably I would use some kind of Enumeration over the map such as the following to achieve my second objective:
Enum.map(mymap, fn {k, v} -> v end)|> Enum.sum{}
But I can't seem to quite crack the syntax to achieve my two aims. Thanks for any help!
If I understand your question correctly, the following should accomplish what you are wanting to do:
def handle_call({:get, getKey}, _from, dict) do
sum = Enum.reduce(dict, 0, fn
({%{key1: key1}, %{val2: val2}}, acc)
when key1 === getKey
and is_integer(val2) ->
val2 + acc
(_, acc) ->
acc
end)
{:reply, sum, dict}
end
See the documentation of Enum.reduce/3 for more information.

tail recursive call in elixir and default parameters

I am writing a simple example in Elixir and although it works I don't really understand how.
defmodule MyList do
def sum([],acc \\ 0), do: acc
def sum([head | tail], acc), do: sum(tail,acc + head)
end
When I call MyList.sum I get the expected result
sum([]) => 0
sum([1,2,3]) => 6
I cannot add a default param in the second sum because the compiler throws an error
def sum/2 has default values and multiple clauses, use a separate clause for declaring defaults
So my question is, how come sum([1,2,3]) works? It does not match any of the definitions.
Is the function still tail recursive?
When you have a multiclause with optional arguments, you can specify defaults as a body-less clause:
defmodule MyList do
def sum(list, acc \\ 0) # sets up default arguments
def sum([],acc), do: acc
def sum([head | tail], acc), do: sum(tail,acc + head)
end
Regarding your example, I'm just guessing, but I think that your code amounts to something like following:
defmodule MyList do
# implicitly generated due to default argument
def sum(list), do: sum(list, 0)
def sum([],acc), do: acc
def sum([head | tail], acc), do: sum(tail,acc + head)
end
Which is why sum([1,2,3]) works as well.
Edit:
The function is definitely tail recursive. If the last thing a function does is a call of another function (or itself), then it is a tail call. So in this case, when we call sum(tail, acc + head), first the arguments are calculated, and then a tail recursive call happens.

Case Statements and Pattern Matching

I'm coding in SML for an assignment and I've done a few practice problems and I feel like I'm missing something- I feel like I'm using too many case statements. Here's what I'm doing and the problem statements for what I'm having trouble with.:
Write a function all_except_option, which takes a string and a string list. Return NONE if the string is not in the list, else return SOME lst where lst is like the argument list except the string is not in it.
fun all_except_option(str : string, lst : string list) =
case lst of
[] => NONE
| x::xs => case same_string(x, str) of
true => SOME xs
| false => case all_except_option(str, xs) of
NONE => NONE
| SOME y=> SOME (x::y)
Write a function get_substitutions1, which takes a string list list (a list of list of strings, the substitutions) and a string s and returns a string list. The result has all the strings that are in some list in substitutions that also has s, but s itself should not be in the result.
fun get_substitutions1(lst : string list list, s : string) =
case lst of
[] => []
| x::xs => case all_except_option(s, x) of
NONE => get_substitutions1(xs, s)
| SOME y => y # get_substitutions1(xs, s)
-
same_string is a provided function,
fun same_string(s1 : string, s2 : string) = s1 = s2
First of all I would start using pattern matching in the function definition
instead of having a "top-level" case statement. Its basically boils down to the
same thing after de-sugaring. Also I would get rid of the explicit type annotations, unless strictly needed:
fun all_except_option (str, []) = NONE
| all_except_option (str, x :: xs) =
case same_string(x, str) of
true => SOME xs
| false => case all_except_option(str, xs) of
NONE => NONE
| SOME y => SOME (x::y)
fun get_substitutions1 ([], s) = []
| get_substitutions1 (x :: xs, s) =
case all_except_option(s, x) of
NONE => get_substitutions1(xs, s)
| SOME y => y # get_substitutions1(xs, s)
If speed is not of importance, then you could merge the two cases in the first function:
fun all_except_option (str, []) = NONE
| all_except_option (str, x :: xs) =
case (same_string(x, str), all_except_option(str, xs)) of
(true, _) => SOME xs
| (false, NONE) => NONE
| (false, SOME y) => SOME (x::y)
But since you are using append (#), in the second function, and since it is not
tail recursive, I don't believe that it your major concern. Keep in mind that
append is potential "evil" and you should almost always use concatenation (and
then reverse your result when returning it) and tail recursion when possible (it
always is).
If you really like the explicit type annotations, then you could do it like this:
val rec all_except_option : string * string list -> string list option =
fn (str, []) => NONE
| (str, x :: xs) =>
case (same_string(x, str), all_except_option(str, xs)) of
(true, _) => SOME xs
| (false, NONE) => NONE
| (false, SOME y) => SOME (x::y)
val rec get_substitutions1 : string list list * string -> string list =
fn ([], s) => []
| (x :: xs, s) =>
case all_except_option(s, x) of
NONE => get_substitutions1(xs, s)
| SOME y => y # get_substitutions1(xs, s)
But that is just my preferred way, if I really have to add type annotations.
By the way, why on earth do you have the same_string function? You can just do the comparison directly instead. Using an auxilary function is just wierd, unless you plan to exchange it with some special logic at some point. However your function names doesn't sugest that.
In addition to what Jesper.Reenberg mentioned, I just wanted to mention that a match on a bool for true and false can be replaced with an if-then-else. However, some people consider if-then-else uglier than a case statement
fun same_string( s1: string, s2: string ) = if String.compare( s1, s2 ) = EQUAL then true else false
fun contains( [], s: string ) = false
| contains( h::t, s: string ) = if same_string( s, h ) then true else contains( t, s )
fun all_except_option_successfully( s: string, [] ) = []
| all_except_option_successfully( s: string, h::t ) = if same_string( s, h ) then t else ( h :: all_except_option_successfully( s, t ) )
fun all_except_option( s: string, [] ) = NONE
| all_except_option( s: string, h::t ) = if same_string( s, h ) then SOME t else if contains( t, s ) then SOME ( h :: all_except_option_successfully( s, t ) ) else NONE

Resources