Erlang - Common items from two lists - list

Erlang Newbie here . Suppose I have two lists which are like this .
L1= [{'Lady in the Water',2.5},
{'Snakes on a Plane',3.5},
{'Just My Luck',3.0},
{'Superman Returns',3.5},
{'You, Me and Dupree',2.5},
{'The Night Listener',3.0}]
and
L2 = [{'Lady in the Water',3.0},
{'Snakes on a Plane',3.5},
{'Just My Luck',1.5},
{'Superman Returns',5.0},
{'You, Me and Dupree',3.5}]
I want the common ratings in a list of tuple like
[{2.5,3.0},{3.5,3.5},{3.0,1.5},{3.5,5.0},{2.5,3.5}]
My code is like this
common_rating(R1,R2)->common_rating(R1,R2,0,0).
common_rating(_X,[],M,N) ->{M,N};
common_rating(X,[Y|Y1],A,B)->
{M,R}=X,
{N,K }= Y,
case M=/=N of
true -> common_rating(X,Y1,A,B);
false -> common_rating(X,[],A+R,B+K)
end.
common_rating_final([],_R2,J) ->J;
common_rating_final([X|X1],R2,J)->
common_rating_final(X1,R2,J++[common_rating(X,R2)]).
To better understand the code
common_rating function expects a tuple of {movie,rating} and finds the same movie and rating from another list(B) and returns {rating,rating_B}
Now common_rating_final recursively goes over a list ,lets say A, and uses common_rating to find {rating_A,rating_B} for all movies that are common in A and B both
but when I run my code
my_module:common_rating_final(L1,L2,[]).
it returns me
[{2.5,3.0},{3.5,3.5},{3.0,1.5},{3.5,5.0},{2.5,3.5},{0,0}]
I can filter the {0,0} part but I think my logic is flawed but could not able to write a code which returns only the common ratings without the {0,0} part .
Please assist .

TL;DR
[{X2, Y2} || {X1, X2} <- L1, {Y1, Y2} <- L2, X1 =:= Y1].
Maybe the "cracks" here can find a better (more efficient, etc.) solution, but this one works. Basically it pattern matches ("deconstruct") the Ls and compares the first element of the tuples, returning the second element if the first ones happen to be equal.
The whole stuff/proof:
gorre#uplink:~$ erl
Erlang/OTP 19 [erts-8.3] [source] [64-bit] [smp:4:4] [async-threads:10] [kernel-poll:false]
Eshell V8.3 (abort with ^G)
1> L1= [{"Lady in the Water",2.5}, {"Snakes on a Plane",3.5}, {"Just My Luck",3.0}, {"Superman Returns",3.5}, {"You, Me and Dupree",2.5}, {"The Night Listener",3.0}].
[{"Lady in the Water",2.5},
{"Snakes on a Plane",3.5},
{"Just My Luck",3.0},
{"Superman Returns",3.5},
{"You, Me and Dupree",2.5},
{"The Night Listener",3.0}]
2> L2 = [{"Lady in the Water",3.0}, {"Snakes on a Plane",3.5}, {"Just My Luck",1.5}, {"Superman Returns",5.0}, {"You, Me and Dupree",3.5}].
[{"Lady in the Water",3.0},
{"Snakes on a Plane",3.5},
{"Just My Luck",1.5},
{"Superman Returns",5.0},
{"You, Me and Dupree",3.5}]
3> [{X2, Y2} || {X1, X2} <- L1, {Y1, Y2} <- L2, X1 =:= Y1].
[{2.5,3.0},{3.5,3.5},{3.0,1.5},{3.5,5.0},{2.5,3.5}]
4>
Notice that I changed the atoms into strings (it works the same way though).

Related

Why does go-cmp Equal() say that the structs are not deeply equal, even though all fields are deeply equal?

I've been using reflect.DeepEqual to deeply compare structs using circular pointers. As that does not work with maps and for better test output, I've switched to go-cmp.
Now I had to take note that even though cmp.Equal is supposed to be a drop-in replacement for reflect.DeepEqual, in cases where the former works correctly, there's a different result in this case, even though it actually is deeply equal.
Can anyone tell me why the result is different in this case and ideally, how to fix it?
Code in Go playground: https://play.golang.com/p/rLWKwMlAfwu
(Updated to use fmt.Printf(), because I couldn't get testing running in playground)
Output for diff:
StrongConnect() mismatch (-want +got):
&⟪ref#0⟫main.Edge{
StartNode: &⟪ref#1⟫main.Node{
Variable: 1,
- Low: &⟪ref#0: 0xc00005c120⟫(...),
+ Low: &⟪ref#0: 0xc00005c120⟫(...),
High: &{StartNode: &⟪ref#1⟫(...), EndNode: &{Variable: 2}, EdgeType: 1, Weight: 1},
},
EndNode: &{Variable: 2},
EdgeType: 0,
Weight: 1,
}
reflect.DeepEqual is more lax than cmp.Equal when comparing structures with cycles (and arguably incorrect).
cmp.Equal will only consider overlapping graphs equivalent if the set of nodes and edges in the graph is the same. Note: Both Node and Edge structs are nodes in this graph comparison.
In your example, the 2 graphs/structs overlap but wantEdge0 is has an extra Edge struct as the root node (prepended).
Here is cut down representation of the cycles in your data structures:
wantEdge0 := &main.Edge{ // n0
StartNode: &main.Node{ // n1
Low: &main.Edge{} // n2
},
}
wantEdge0.StartNode.Low.StartNode = wantEdge0.StartNode // n1
got := wantEdge0.StartNode.Low // n2
Hence there are the 2 different cycles:
wantEdge0 [n0] -> wantEdge0.StartNode [n1] -> got [n2] -> wantEdge0.StartNode [n1]
got [n2] -> wantEdge0.StartNode [n1] -> got [n2]
Here is a simple example that demonstrates this difference between reflect.DeepEqual and cmp.Equal:
package main
import (
"fmt"
"reflect"
"github.com/google/go-cmp/cmp"
)
type Node struct {
Next *Node
Value int
}
func main() {
a0 := &Node{}
a1 := &Node{}
a2 := &Node{}
a0.Next = a1
a1.Next = a2
a2.Next = a1
b1 := &Node{}
b2 := &Node{}
b1.Next = b2
b2.Next = b1
fmt.Println("DeepEqual\tcmp.Equal")
fmt.Printf("\t%v\t%v\t\tIndependent graphs\n", reflect.DeepEqual(a1, b1), cmp.Equal(a1, b1))
fmt.Printf("\t%v\t%v\t\tSame graph, different root\n", reflect.DeepEqual(a1, a2), cmp.Equal(a1, a2))
fmt.Printf("\t%v\t%v\t\tSame graph prepend vs no prepend\n", reflect.DeepEqual(a0, a1), cmp.Equal(a0, a1))
}
Output:
$ ./compare
DeepEqual cmp.Equal
true true Independent graphs
true true Same graph, different root
true false Same graph prepend vs no prepend
Solution: I would recommend allocating completely separate structures for your want struct and the test input. This way the want and got structs won't overlap and they should compare as intended.
References:
https://github.com/google/go-cmp/commit/5a6f75716e1203a923a78c9efb94089d857df0f6
https://github.com/google/go-cmp/issues/74

Recursively Assigning One List Element to Another in Prolog

This is a homework assignment and my first experience with Prolog. My goal is to create a list of Assignments from a list of people and a list of tasks. If a person has the letter identifier which matches the tasks then that persons ID and the Tasks ID are matched up and placed in a list of Assignments. My function prints out a list but it does not look like it is comparing all the elements. A sample input: schedule([p1,p2,p3],[t1,t2],Result). A sample output would look like [[p1,t1],[p2,t2][p3,t1],[p3,t2]].
What I have so far:
%%
%% person(ID, TASK_CAPABILITIES, AVAILABLE_HOURS)
%%
%% How many hours each person has available and what classes of tasks they
%% are capable of performing.
%%
person(p1, [c,a], 20).
person(p2, [b], 10).
person(p3, [a,b], 15).
person(p4, [c], 30).
%%
%% task(ID, REQUIRED_HOURS, TASK_CLASS)
%%
%% How long each task requires and what class it falls under.
%%
task(t1, a, 5).
task(t2, b, 10).
task(t3, c, 15).
task(t4, c, 10).
task(t5, a, 15).
task(t6, b, 10).
%test arithmetic functions
add(X, Y, Z) :- Z is X + Y.
subtract(X,Y,Z) :- Z is X - Y.
schedule([],[],[]).
schedule(People,
[Task|OtherTasks],
[[PersonId, TaskId]|RestOfAssignments]):-
member(PersonId, People),
person(PersonId, PersonCapabilities,_),
member(TaskId, [Task|OtherTasks]),
task(TaskId, TaskType,_),
member(TaskType, PersonCapabilities),
schedule( _, OtherTasks, RestOfAssignments).
My reasoning behind what I wrote was that the list of People would be compared to each task, then that task would be replaced by the next task and the comparison would repeat. What I see in the trace of this function instead is that the tasks are being removed from the list but are only compared to the first two People. My question is how can I get the schedule function to check the full list of people for each task?
Your problem seems ill specified, and you are simplifying too much... the code should keep into account hours availability as well as memberships. Ignoring this problem, select/3 instead of member/2 could help to model a naive solution:
schedule([],_,[]).
% peek a suitable task for PersonId
schedule([PersonId|People], Tasks, [[PersonId, TaskId]|RestOfAssignments]):-
select(TaskId, Tasks, RestTasks),
person(PersonId, PersonCapabilities,_),
task(TaskId, TaskType,_),
memberchk(TaskType, PersonCapabilities),
schedule(People, RestTasks, RestOfAssignments).
% if no suitable task for PersonId
schedule([_PersonId|People], Tasks, Assignments):-
schedule(People, Tasks, Assignments).
yields these solutions
?- schedule([p1,p2,p3],[t1,t2],Result).
Result = [[p1, t1], [p2, t2]] ;
Result = [[p1, t1], [p3, t2]] ;
Result = [[p1, t1]] ;
Result = [[p2, t2], [p3, t1]] ;
Result = [[p2, t2]] ;
Result = [[p3, t1]] ;
Result = [[p3, t2]] ;
Result = [].

prolog, i have list of structure how to Extract data and return new list of other structure?

I implementing Family program in prolog i have a problem to implement some rules.
first of all i implement this rule:
number_of_children_couple(_list):-
findall(children(_f,_m,_n),children(_f,_m,_n),_list).
return list:
19 ?- number_of_children_couple(_list).
_list = [children(mordechai, miriam, 1), children(salax, naima, 1), children(eli, bella, 2), children(..., ..., ...)|...].
my problem is how to implement :
number_of_children_person(_list28,list_person):-
first argument:
_list28 = _list //the above list ,that return from the rule
and second argument is :
list_person = [children(mordechai, 1), children(salax, 1),children(eli, 2),children(..., ...)|...]
and i also use with:
%_num is number of children for couple
children(_father,_mother,_num):-
couple(_mother,_father),
findall(_child,parents(_mother,_father,_child),_children),
length1(_children,_num).
%_num is number of children for _person
children(_person,_num):-
gender(_person,_),
findall(_child,parent(_person,_child),_list),
length1(_list,_num).
if what you want is to drop an argument from children/3 structure, can be done in a number of ways, the simpler being
number_of_children_person([],[]).
number_of_children_person([children(A,_,C)|R],[children(A,C)|T]) :-
number_of_children_person(R,T).
or more succintly
number_of_children_person(L3,L2) :-
findall(children(A,C), member(children(A,B,C),L3), L2).

Minimal transversal of a Hypergraph

Hi This is my first post, so please go easy on me. I tried going through an algorithm Dualize and Advance for generating maximal frequent item sets. I considered an example as follows
Transactions
abcde
ace
bd
abc
and minimum frequency threshold as 2.
Now, I have a problem understanding how to generate 'minimal transversals' part of the algorithm.
I know that transversal is a subset of vertices of the hypergraph that intersects every hyper edge. So the initial set of minimal transversals should be {a,b,c,d,e} if I am not wrong.
Can you please explain me this part of 'minimal transversal' w.r.t the transactions.
Ok, I ll try to answer my question.
At the end of first iteration of the algorithm and for the given transactions, {abc} is emanated as maximal frequent itemset. Here is how I understood,
minimal transversal X = S1' = {a,b,c,d,e}
S2 = {abc} is maximal and S2' = {de}
Find minimal transversal of S2' which is {d,e}
Now, X = {d,e}, consider 'd' ,
S3 = {bd} is maximal and S3' = {ace}
Now, consider 'e'
S4 = {ace} is maximal and meanwhile I get {ad} , {be} ,{cd} and {de} as minimal transversals which are infrequent.
A subset T of V is a transversal (or hitting set) of H if it
intersects all the hyperedges of H,
'minimal transversal' -> the smallest possible set that we get.
Also, we enforce ordering in our algorithm a>b>c>d>e
Iteration 1:
S1 = {}
S1' = {abcde}
Tr = {a,b,c,d,e} [All nodes are required to cut Si']
Iteration 2:
S2 = {abc}
S2' = {de}
Tr = {d,e} [Two nodes are required to cut Si']
Iteration 3:
S3 = {abc, bd}
S3' = {de, ace}
Tr = {e, cd, ad} [Three nodes are required to cut Si']
Iteration 4:
S4 = {abc, bd, ace}
S4' = {de, bd, ace}
Tr = {de, cd, ad, be} [Four nodes are required to cut Si']
All minimal transversals Tr are infrequent so the algorithm ends.

Why this behavior when coercing a list to character via as.character()?

In the process of (mostly) answering this question, I stumbled across something that I feel like I really should already have seen before. Let's say you've got a list:
l <- list(a = 1:3, b = letters[1:3], c = runif(3))
Attempting to coerce l to various types returns an error:
> as.numeric(l)
Error: (list) object cannot be coerced to type 'double'
> as.logical(l)
Error: (list) object cannot be coerced to type 'logical'
However, I'm apparently allowed to coerce a list to character, I just wasn't expecting this result:
> as.character(l)
[1] "1:3"
[2] "c(\"a\", \"b\", \"c\")"
[3] "c(0.874045701464638, 0.0843329173512757, 0.809434881201014)"
Rather, if I'm allowed to coerce lists to character, I would have thought I'd see behavior more like this:
> as.character(unlist(l))
[1] "1" "2" "3" "a" "b"
[6] "c" "0.874045701464638" "0.0843329173512757" "0.809434881201014"
Note that how I specify the list elements originally affects the output of as.character:
l <- list(a = c(1,2,3), b = letters[1:3], c = runif(3))
> as.character(l)
[1] "c(1, 2, 3)"
[2] "c(\"a\", \"b\", \"c\")"
[3] "c(0.344991483259946, 0.0492411875165999, 0.625746068544686)"
I have two questions:
How is as.character dredging up the information from my original creation of the list l in order to spit out 1:3 versus c(1,2,3).
In what circumstances would I want to do this, exactly? When would I want to call as.character() on a list and get output of this form?
For non-trivial lists, as.character uses deparse to generate the strings.
Only if the vector is integer and 1,2,3,...,n - then it deparses as 1:n.
c(1,2,3) is double whereas 1:3 is integer...
No idea :-)
...but look at deparse if you want to understand as.character here:
deparse(c(1L, 2L, 3L)) # 1:3
deparse(c(3L, 2L, 1L)) # c(3L, 2L, 1L)
deparse(c(1, 2, 3)) # c(1, 2, 3)
The help file does say
For lists it deparses the elements individually, except that it extracts the first element of length-one character vectors.
I'd seen this before in trying to answer a question [not online] about grep. Consider:
> x <- list(letters[1:10],letters[10:19])
> grep("c",x)
[1] 1 2
grep uses as.character on x, with the result that, since both have c( in them, both components match. That took a while to figure out.
On "Why does it do this?", I'd guess that one of the members of R core wanted it to do this.