List comprehension AND guards - erlang

How to implement AND guards in list comprehensions? Separating the guards with comma seems to word as OR:
1> rd(r, {a, b}).
r
2> L = [#r{a = 1, b =2}, #r{a = 1, b = 3}].
[#r{a = 1,b = 2},#r{a = 1, b = 3}]
3> [X || X <- L, X#r.a =/= 1, X#r.b =/= 2].
[]
Thanks a lot.

That's definitely an AND. The first element fails both tests; the second fails the X#r.a =/= 1 test.
If you want OR, simply use the orelse operator:
2> [X || X <- L, X#r.a =/= 1 orelse X#r.b =/= 2].
[#r{a = 1,b = 3}]

Related

Increase list size using list comprehension in erlang

A = [1,2,3]
The output should be:
[1,one,2,two,3,three]
Is it possible to get such an output?
Yes, you can put two clauses in the comprehension and make the second one return two elements for each element in the first one:
1> F = fun
1> (1) -> "one";
1> (2) -> "two";
1> (3) -> "three"
1> end.
#Fun<erl_eval.6.127694169>
2> [B || A <- [1, 2, 3], B <- [A, F(A)]].
[1,"one",2,"two",3,"three"]
i think the out put of last code would be
[[1 ,"one"] , [2, "two"] , [3 , "tree"]].
some right answer will be
lists:append([begin T = case I of
1 -> "One" ;
2->"Two";
3->"Three";
_ -> "" end ,
[I ,T] end
|| I <- lists:seq(1,3)]).

Empty Map Pattern matches even for non-empty Map

The problem I am trying to solve states
Write a function map_search_pred(Map, Pred) that returns the first
element {Key,Value} in the map for which Pred(Key, Value) is true.
My attempt looks like
map_search_pred(#{}, _) -> {};
map_search_pred(Map, Pred) ->
[H|_] = [{Key, Value} || {Key, Value} <- maps:to_list(Map), Pred(Key, Value) =:= true],
H.
When I run this, I see output as
1> lib_misc:map_search_pred(#{1 => 1, 2 => 3}, fun(X, Y) -> X =:= Y end).
{}
2> lib_misc:map_search_pred(#{1 => 1, 2 => 3}, fun(X, Y) -> X =:= Y end).
{}
3> maps:size(#{}).
0
4>
How am I so sure?
I pulled out the first clause so it looks like
map_search_pred(Map, Pred) ->
[H|_] = [{Key, Value} || {Key, Value} <- maps:to_list(Map), Pred(Key, Value) =:= true],
H.
and run again
1> lib_misc:map_search_pred(#{1 => 1, 2 => 3}, fun(X, Y) -> X =:= Y end).
{1,1}
2> lib_misc:map_search_pred(#{}, fun(X, Y) -> X =:= Y end).
** exception error: no match of right hand side value []
in function lib_misc:map_search_pred/2 (/Users/harith/code/IdeaProjects/others/erlang/programmingErlang/src/lib_misc.erl, line 42)
3>
According to map documentation:
Matching an expression against an empty map literal will match its type but no variables will be bound:
#{} = Expr
This expression will match if the expression Expr is of type map, otherwise it will fail with an exception badmatch.
However erlang:map_size can be used instead:
map_search_pred(Map, _) when map_size(Map) == 0 ->
{};
map_search_pred(Map, Pred) ->
[H|_] = [{Key, Value} || {Key, Value} <- maps:to_list(Map), Pred(Key, Value) =:= true],
H.

F# Array Of String: concatenating values

I have an array like this:
let items = ["A";"B";"C";"D"]
I want to transform it into an array like this:
let result = ["AB";"AC";"AD";"BC";"BD";"CD"]
I can't find anything in the language spec that does this - though I might be searching incorrectly. I thought of Seq.Fold like this:
let result = items |> Seq.fold(fun acc x -> acc+x) ""
but I am getting "ABCD"
Does anyone know how to do this? Will a modified CartesianProduct work?
Thanks in advance
What you have there are lists, not arrays -- lists use the [...] syntax, arrays use the [|...|] syntax.
That said, here's a simple implementation:
let listProduct (items : string list) =
items
|> List.collect (fun x ->
items
|> List.choose (fun y ->
if x < y then Some (x + y)
else None))
If you put it into F# interactive:
> let items = ["A"; "B"; "C"; "D"];;
val items : string list = ["A"; "B"; "C"; "D"]
> items |> listProduct |> Seq.toList;;
val it : string list = ["AB"; "AC"; "AD"; "BC"; "BD"; "CD"]
Something like this should do it:
items
|> List.map (fun x -> items |> List.map (fun y -> (x, y)))
|> List.concat
|> List.filter (fun (x, y) -> x < y)
|> List.map (fun (x, y) -> x + y)
|> List.sort
I don't know if it's efficient for large lists, but it does produce this output:
["AB"; "AC"; "AD"; "BC"; "BD"; "CD"]
Breakdown
The first step produces a list of list of tuples, by mapping items twice:
[[("A", "A"); ("A", "B"); ("A", "C"); ("A", "D")];
[("B", "A"); ("B", "B"); ("B", "C"); ("B", "D")];
[("C", "A"); ("C", "B"); ("C", "C"); ("C", "D")];
[("D", "A"); ("D", "B"); ("D", "C"); ("D", "D")]]
Second, List.concat turns the list of list into a single list:
[("A", "A"); ("A", "B"); ("A", "C"); ("A", "D"); ("B", "A"); ("B", "B");
("B", "C"); ("B", "D"); ("C", "A"); ("C", "B"); ("C", "C"); ("C", "D");
("D", "A"); ("D", "B"); ("D", "C"); ("D", "D")]
Third, List.filter removes the tuples where the first element is equal to or larger than the second element:
[("A", "B"); ("A", "C"); ("A", "D"); ("B", "C"); ("B", "D"); ("C", "D")]
Fourth, List.map produces a list of concatenated strings:
["AB"; "AC"; "AD"; "BC"; "BD"; "CD"]
Finally, List.sort sorts the list, although in this case it's not necessary, as the list already has the correct order.
You might also consider using Seq.distinct to remove duplicates, if there are any.
You could create a function to create a list of all head/tail pairs in a list:
let rec dec = function
| [] -> []
| (x::xs) -> (x, xs) :: dec xs
or a tail-recursive version:
let dec l =
let rec aux acc = function
| [] -> acc
| (x::xs) -> aux ((x, xs)::acc) xs
aux [] l |> List.rev
you can then use this function to create your list:
let strs (l: string list) = l |> dec |> List.collect (fun (h, t) -> List.map ((+)h) t)
I'd do it like this:
let rec loop = function
[] -> []
| x :: xs -> List.map ((^) x) xs # loop xs
This has the advantage of not building every pair of elements from the list only to discard half. (I'll leave getting rid of the append as an exercise :-)
For me, it is a bit easier to tell what's going on here compared some of the other proposed solutions. For this kind of problem, where to process an element x you need also access to the rest of the list xs, standard combinators won't always make solutions clearer.
let items = ["A";"B";"C";"D"]
let rec produce (l: string list) =
match l with
// if current list is empty or contains one element - return empty list
| [] | [_] -> []
// if current list is not empty - match x to head and xs to tail
| x::xs ->
[
// (1)
// iterate over the tail, return string concatenation of head and every item in tail
for c in xs -> x + c
// apply produce to tail, concat return values
yield! produce xs
]
1st iteration: l = [A, B, C, D] - is not empty, in second match case we'll have x = A, xs = [B, C, D]. 'for' part of the list expression will yield [AB, AC, AD] and result of applying produce to xs.
2nd iteration:l = [B, C, D] is not empty so second match case we'll have x = B, xs = [C, D]. 'for' part of the list expression will yield [BC, BD] and result of applying produce to xs.
3rd iteration:l = [C, D] is not empty in second match case we'll have x = C, xs = [D]. 'for' part of the list expression will yield [CD] and result of applying produce to xs.
4th iteration:l = [D] contains one element -> return empty list.
Final result will be concatenation of [AB, AC, AD] ++ [BC, BD] ++ [CD]
This is an apt motivating example for implementing a List monad in F#. Using F# computation expressions, we get:
type ListMonadBuilder() =
member b.Bind(xs, f) = List.collect f xs
member b.Delay(f) = fun () -> f()
member b.Let(x, f) = f x
member b.Return(x) = [x]
member b.Zero() = []
let listM = new ListMonadBuilder()
Now, to solve the original problem we simply use our List monad.
let run = listM {
let! x = ['A' .. 'D']
let! y = List.tail [ x .. 'D']
return string x + string y
}
run();; in F# Interactive will return the desired result.
For another example of using the List monad, we can get the Pythagorean triples <= n.
let pythagoreanTriples n = listM {
let! c = [1 .. n]
let! b = [1 .. c]
let! a = [1 .. b]
if a*a + b*b = c*c then return (a, b, c)
}
Running pythagoreanTriples 10 ();; in F# interactive returns:
val it : (int * int * int) list = [(3, 4, 5); (6, 8, 10)]

Erlang: proplists:get_value/2 or pattern matching?

I have a list of tuples that has always the same form (i.e. the tuples come always in the same order):
1> L = [{a, 1}. {b,2}, {c, 3}, {d, 4}].
Knowing that the list has only a few elements, what is the best way to extract the values associated to the keys?
Suppose the list is passed as argument to a function, to extract the values should I use:
proplists:get_value(a, L).
proplists:get_value(b, L).
...
proplists:get_valus(d, L).
Or should I simply use pattern matching as:
[{a, 1}. {b,2}, {c, 3}, {d, 4}] = L.
If you really know your lists is in same form pattern matching is simplest
[{a, A}, {b, B}, {c, C}, {d, D}] = L,
you can compare it with following
[A, B, C, D] = [ proplists:get_value(X, L) || X <- [a,b,c,d] ],
or
A = proplists:get_value(a, L),
B = proplists:get_value(b, L),
C = proplists:get_value(c, L),
D = proplists:get_value(d, L),
or
[A, B, C, D] = [ V || Key <- [a,b,c,d], {K, V} <- L, K =:= Key ],
Pattern matching will be also fastest. You can also use lists:keyfind/3 which is implemented as Bif and is way faster than proplist:get_value/2 but it doesn't matter for short lists.

searching in a list for a record with specific fields and ignoring the rest

I have a record defined as:
1> rd(fact, {a,b,c}).
fact
I create three records and put them in a list
2> F1 = #fact{a=1,b=1,c=1}.
#fact{a = 1,b = 1,c = 1}
(3> F2 = #fact{a=2,b=2,c=2}.
#fact{a = 2,b = 2,c = 2}
3> F3 = #fact{a=3,b=3,c=3}.
#fact{a = 3,b = 3,c = 3}
4> L = [F1,F2,F3].
[#fact{a = 1,b = 1,c = 1},
#fact{a = 2,b = 2,c = 2},
#fact{a = 3,b = 3,c = 3}]
Now, I want to check if the list contains a record in which 'a' is 1 and I don't care for the rest of the fields
(dilbert#Martin-PC)21> lists:member(#fact{a=1}, L).
false
(dilbert#Martin-PC)23> lists:member(#fact{a=1,b=1,c=1}, L).
true
How can I accomplish it?
Or you could use keyfind.
lists:keyfind(1, #fact.a, L).
Records are pure syntactic sugar. When you don't specify the values of the other fields in a record declaration the atom 'undefined' is used. Therefore your search is for:
#fact{a=1, b='undefined', c='undefined'}
... which of course doesn't exist.
Try this instead:
lists:any(fun(#fact{a=A}) -> A =:= 1 end, L).
Or list comprehension:
OneList = [E || E <- L, E#fact.a =:= 1]

Resources