Prolog. Count members in database or List - prolog

I have a database i want to write a query to return the total members in the database
member(paul,100). member(john,101). member(ryan,102). member(jabouki,103).
Should Return 4
I also have a list and i want to return the number of persons in the list
memberlist([ant,cat,sat,bat]).
Should Return 4
Query I have thus far that only return the items in the database and list.
member(MemberName,_).
memberlist(Y)

findall(X, member(X,_), L), length(L,N).
Will give you the following results:
L = [paul, john, ryan, jabouki],
N = 4.
Greetings
Solick

Related

Prolog - bagof - case of no results

I have activity-users relations:
% Signature: activity(Name,Day)/2
% Purpose: describe an activity at the country club and the day it takes place
%
activity(swimming,sunday).
activity(ballet,monday).
activity(judu,tuesday).
activity(soccer,wednesday).
activity(art,sunday).
activity(yoga,tuesday).
% Signature: participate(Child_name,Activity)/2
% Purpose: registration details
%
participate(dany,swimming).
participate(dany,ballet).
participate(dana,soccer).
participate(dana,judu).
participate(guy,judu).
participate(shai,soccer).
I want to create query to get all the participants of activity.
So I use bagof:
activity_participants_list(Activity_Name,List) :- ( bagof(X, participate(X,Activity_Name), List)).
But I want to get List = [] when query: activity_participants_list(dancing,List)
So I added ; List = [] to the end of the function but then
when query
activity_participants_list(A,B) i also get empty list as an answer
And query activity_participants_list(A, []) return true.
I also would like to get yoga with empty list as an answer to activity_participants_list(A,B)
What is the right way to do it?
As you found, bagof fails when the goal has no solutions. This is dumb design, unfortunately. As you also found, ; is tricky to use. Try not to be tempted to use it.
findall works similarly to bagof, and it does give an empty list of results if the goal has no solutions:
activity_participants(Activity, Participants) :-
activity(Activity, _), % we are interested in a concrete activity
findall(Participant, participate(Participant, Activity), Participants).
?- activity_participants(Activity, Participants).
Activity = swimming,
Participants = [dany] ;
Activity = ballet,
Participants = [dany] ;
Activity = judu,
Participants = [dana, guy] ;
Activity = soccer,
Participants = [dana, shai] ;
Activity = art,
Participants = [] ;
Activity = yoga,
Participants = [].
The role of the activity(Activity, _) goal is to bind Activity, this basically forces findall to succeed several times, grouped by activity. If we removed this goal, we wouldn't group by activity, and we would just get a list of all the people participating in any activity:
?- activity_participants(Activity, Participants).
Participants = [dany, dany, dana, dana, guy, shai].

Using COUNTIFS to find only unique values

I currently have a table with five columns:
A = Campaign
B = Person
C = Opportunity Name
D = Total Cost of Campaign
E = Date
I'm trying to use COUNTIFS to count the number of rows that match the exact value in cell H2 to column A and has a date range, in column E, that is greater than the value in cell I2.
I have something like this so far:
=countifs($A$2:$A, $H$2, $E$2:$E, ">"&$I$2).
However, I'm having a tough time to trying to dedupe this - it should only count unique rows based on the data in column C, where duplicate names exist. Please refer to my data table as reference:
Campaign Person Opportunity Name Total Cost of Campaign Date
A Bob Airbnb 5000 3/2/2017
B Jim Sony 10000 3/2/2017
B Jane Coca-Cola 10000 3/2/2017
C Jim Sony 200 3/2/2017
B Daniel Sony 10000 3/2/2017
B April Coca-Cola 10000 3/5/2017
For example:
=countifs($A$2:$A, $H$2, $E$2:$E, ">"&$I$2)
with B in H2 and 3/1/2017 in I2 will give me a result of 4 but I'm really trying to extract a value of 2, given that there are only two unique names in Column C (Sony and Coca-Cola).
How could I do this?
You need to include column C in your formula and use COUNTUNIQUE function as #Jeeped have suggested. Here is the final formula that you can use:
=COUNTUNIQUE(IFERROR(FILTER(C:C,A:A=H2,E:E>I2)))
Use COUNTUNIQUE with QUERY
=countunique(QUERY(A:E,"Select C where A = '"&H2&"' and E > date '" & text(I2,"yyyy-mm-dd") & "'",0))

Accessing a particular element in a list

I am new to Prolog and wanted to access specific elements of the list.For eg-
L=[name,age,height,weight,gender]
How can I access age and height from this list as I want to compare them with some given values???
A list is not intended to be used as a record. Anyway, just use unification
L = [Name,Age,Height,Weight,Gender],
( Gender == male -> ... ; ... )

Prolog beginner here

hasAccount(Person,Bank,Amount) – the Person has an account at the Bank with the balance Amount,
lives(Person,City) – the Person lives in the City,
created(Person,Bank,Month,Year) – the Person opened an account at the Bank in Month of the Year.
With the predicates above, I want to try few things, say printing a list of names with accounts they have, I tried the following query.
?- hasAccount(Someone, Bank1, Balance1), hasAccount(Someone, Bank2, Balance2), not Bank1 = Bank2.
Someone = ann
Bank1 = metro_credit_union
Balance1 = 1000
Bank2 = toronto_dominion
Balance2 = 12000
Yes (0.00s cpu, solution 1, maybe more)
Someone = ann
Bank1 = toronto_dominion
Balance1 = 12000
Bank2 = metro_credit_union
Balance2 = 1000
Can you please explain why do I have reversed list again and what I can do to prevent this happening? Thank you!
why I have reversed list again
it happens since you're not stating in your query enough info to break symmetry.
You can use instead
?- hasAccount(Someone, Bank1, Balance1), hasAccount(Someone, Bank2, Balance2), Bank1 #< Bank2.
or some builtin, like findall/3 (or bagof/3)

How to combine rows using LINQ?

Say I have an entity with following properties [Id, UserName, ProductName], where Id is the PK, and other fields are not unique, so the rows with same UserName repeat multiple times.
For one of the views I need to get a collection that would have unique UserName, and other fields would be combined together using string concatenation or something similar.
If I have
[0, John, Alpha]
[1, Mary, Beta]
[2, John, Gamma]
I need a query that would get me a collection like
[John, Alpha Gamma]
[Mary, Beta]
And it would be awesome if all that could be accomplished on the database side without loading the entities.
You are looking for GroupBy():
var results = context.MyEntities.GroupBy( x => x.UserName);
foreach (var item in results)
{
Console.WriteLine("{0} : {1}", item.Key, string.Join(",", item.Select( x=> x.ProductName));
}

Resources