Get all keys from nested map - dictionary

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.

Related

Create a repeat function in SML

I am working on creating a function called repeat that takes two int lists lst1 and lst2. Assume that lst2 only has nonnegative integers, repeats the integers in the first list lst1 according to the numbers indicated by the second list lst2. If both lists are empty, return an empty list. You may need a local function.
Example:
repeat ([1,2,3], [4,0,3]) -> [1,1,1,1,3,3,3]
I am having a little trouble with getting started with this function. What should I put after the xs?
fun repeat(lst1, lst2) =
case lst1 of
[] => []
| x::xs' => [] (* what should I put here *)
Like any recursion problem, what's your base case? I'd say in this case it's both lists are empty and it gives you an empty list.
fun repeat([], []) = []
What if one is empty but the other isn't? That's a failure. Let's define an exception we can throw if this happens.
exception MismatchedArguments;
fun repeat([], []) = []
| repeat([], _) = raise MismatchedArguments
| repeat(_, []) = raise MismatchedArguments
Now the real question is what we do the rest of the time. Fortunately, SML makes it easy to pattern match both lists and extract their first elements.
exception MismatchedArguments;
fun repeat([], []) = []
| repeat([], _) = raise MismatchedArguments
| repeat(_, []) = raise MismatchedArguments
| repeat(x::xs, y::ys) = ...
At this point, we need a recursive function to repeat an element of the list a certain number of times. As with the overall function, here we see the two hallmarks of recursion: at least one base "exit" condition, and an update step where we converge toward the base condition by updating n to n - 1.
exception MismatchedArguments;
fun repeat([], []) = []
| repeat([], _) = raise MismatchedArguments
| repeat(_, []) = raise MismatchedArguments
| repeat(x::xs, y::ys) =
let
fun repeat'(_, 0) = []
| repeat'(x, n) = x :: repeat'(x, n - 1)
in
...
end
Now, we just need to put it all together, by feeding x and y to repeat' and then concatenating that with the result of calling repeat again with xs and ys. By doing this, we converge down toward the base case of repeat([], []) or we may converge toward a mismatched scenario where a MismatchedArguments exception is raised.
exception MismatchedArguments;
fun repeat([], []) = []
| repeat([], _) = raise MismatchedArguments
| repeat(_, []) = raise MismatchedArguments
| repeat(x::xs, y::ys) =
let
fun repeat'(_, 0) = []
| repeat'(x, n) = x :: repeat'(x, n - 1)
in
repeat'(x, y) # repeat(xs, ys)
end
Now repeat([1, 2, 3], [4, 0, 3]) will yield [1, 1, 1, 1, 3, 3, 3].

A function that compare a two lists of string

I am a new at F# and i try to do this task:
Make a function compare : string list -> string list -> int that takes two string lists and returns: -1, 0 or 1
Please help. I spend a lot of time, and i can not understand how to implement this task.
Given the task I assume what your professor wants to teach you with this exercise. I'll try to give you a starting point without
Confusing you
Presenting a 'done-deal' solution
I assume the goal of this task is to work with recursive functions and pattern matching to element-wise compare their elements. It could looks somewhat like this here
open System
let aList = [ "Apple"; "Banana"; "Coconut" ]
let bList = [ "Apple"; "Banana"; "Coconut" ]
let cList = [ "Apple"; "Zebra" ]
let rec doSomething f (a : string list) (b : string list) =
match (a, b) with
| ([], []) ->
printfn "Both are empty"
| (x::xs, []) ->
printfn "A has elements (we can unpack the first element as x and the rest as xs) and B is empty"
| ([], x::xs) ->
printfn "A is empty and B has elements (we can unpack the first element as x and the rest as xs)"
| (x::xs, y::ys) ->
f x y
printfn "Both A and B have elements. We can unpack them as the first elements x and y and their respective tails xs and ys"
doSomething f xs ys
let isItTheSame (a : string) (b : string) =
if String.Equals(a, b) then
printfn "%s is equals to %s" a b
else
printfn "%s is not equals to %s" a b
doSomething isItTheSame aList bList
doSomething isItTheSame aList cList
The example has three different lists, two of them being equal and one of them being different. The doSomething function takes a function (string -> string -> unit) and two lists of strings.
Within the function you see a pattern match as well as a recursive call of doSomething in the last match block. The signatures aren't exactly what you need and you might want to think about how to change the parametrization for cases where you don't want to stop the recursion (the last match block - if the strings are equal you want to keep on comparing, right?).
Just take the code and try it out in FSI. I'm confident, that you'll find the solution 🙂
In F# many collections are comparable if their element type is:
let s1 = [ "a"; "b" ]
let s2 = [ "foo"; "bar" ]
compare s1 s2 // -5
let f1 = [ (fun () -> 1); fun () -> 2 ]
let f2 = [ (fun () -> 3); fun () -> 42 ]
// compare f1 f2 (* error FS0001: The type '(unit -> int)' does not support the 'comparison' constraint. *)
so
let slcomp (s1 : string list) s2 = compare s1 s2 |> sign
Posting for reference as the original question is answered already.

How to list even numbers in erlang using recursive functions?

How to generate even numbers in this way using recursive functions in Erlang.
Note: The length of the output list is the input of the function func
Example:
> mod:func(5).
[2,4,6,8,10]
Many ways to do that in erlang, I suggest:
with sequence generators
doubles(Number)->
lists:seq(2,Number*2,2).
with list comprehensions
doubles(Number)->
[X*2 || X <- lists:seq(1,Number)].
the recursive way
doubles(Max)->
doubles(1,Max).
doubles(Max,Max)->
[Max*2];
doubles(Val,Max)->
[Val*2]++doubles2(Val+1,Max).
Here's an example module:
-module(even_numbers).
-export([get_first_n/1]).
get_first_n(Count) ->
get_first_n(Count, 2).
get_first_n(1, Current) ->
[Current];
get_first_n(Count, Current) ->
[Current] ++ f(Count - 1, Current + 2).
There is one simple and natural Erlangish way:
func(N) when is_integer(N) ->
func(2, N).
func(X, N) when N > 0 ->
[X | func(X+2, N-1)];
func(_, _) -> [].
For me tail-recursive way is more natural Erlang way:
func(N) when is_integer(N) andalso (N >= 0) ->
func(N, 1, []).
func(0, _, Acc) ->
lists:reverse(Acc);
func(N, I, Acc) ->
func(N - 1, I + 1, [I*2|Acc]).

Return the index for a list from a list in Erlang

I've been practicing using recursion to define the index in Erlang. Here I need to implement a function to return the index for a list from a list.
eg.
([2, 4, 4], [1, 1, 2, 4, 4, 3, 4 ]) ----> 2
([1, 3], [5, 2, 2, 3, 1, 3, 5]) ----> 4
([1], [3, 2, a, {1, 1}, 1] ----> 4
Here is my code:
-module(project).
-export([index/2]).
index([X|XS],[_]) -> index([X|XS],[_],1).
index(_,[],_) -> [];
index([X|XS],[X|_], ACC) -> ACC;
index([X|XS],[_|rest],ACC) ->index([X|XS],rest,ACC+1).
I modified and coded logically but it still can not being compiled. I hope someone who can help me with it. Thanks!
Just for fun, here is an implementation that is not written a very clean way, but illustrates the techniques I think you are looking for. Note there are two basic states: "checking" and "matching".
-module(sublistmatch).
-export([check/2]).
check(Segment, List) ->
SegLen = length(Segment),
ListLen = length(List),
Index = 1,
check(Segment, List, SegLen, ListLen, Index).
check(S, S, _, _, I) ->
{ok, I};
check(_, _, SL, LL, _) when SL >= LL ->
nomatch;
check(S = [H|Ss], [H|Ls], SL, LL, I) ->
case matches(Ss, Ls) of
true -> {ok, I};
false -> check(S, Ls, SL, LL - 1, I + 1)
end;
check(S, [_|L], SL, LL, I) ->
check(S, L, SL, LL - 1, I + 1).
matches([H|S], [H|L]) -> matches(S, L);
matches([], _) -> true;
matches(_, _) -> false.
Note that this depends on knowing the lengths of both the segment you are checking for, and the current length of the remaining list to check. Consider why this is necessary. Also consider how using the utility function matches/2 gives us a natural place to explore whether an option matches, and backtracks if it does not.
In real programs you would use the standard library functions such as lists:prefix/2, lists:suffix/2, or sets:is_subset/2, or maybe some key or member operation over a gb_tree, dict, map or array depending on the situation.
To Compile the code you have to change it to:
-module(project).
-export([index/2]).
%%index([X|XS],[_]) -> index([X|XS],[_],1).
index([X|XS],List) -> index([X|XS],List,1).
%% you shuld not pass '_' as parameter it's will be marked as unbound
index(_,[],_) -> [];
index([X|XS],[X|_], ACC) -> ACC;
%%index([X|XS],[_|rest],ACC) ->index([X|XS],rest,ACC+1).
index([X|XS],[_|Rest],ACC) ->index([X|XS],Rest,ACC+1).
%% rest is an atom, it's not the case you need to use here.
%%Variables should start with upper case letter.
This code will compiled but wrong results as some cases.

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.

Resources