11.2.3 setof/3

The setof/3 predicate is basically the same as bagof, but with one useful difference: the lists it contains are ordered and contain no redundancies (that is, each item appears in the list only once).

For example, suppose we have the following database

age(harry,13).
age(draco,14).
age(ron,13).
age(hermione,13).
age(dumbledore,60).
age(hagrid,30).

Now suppose we want a list of everyone whose age is recorded in the database. We can do this with the query:

findall(X,age(X,Y),Out).
 
X = _8443  
Y = _8448  
Out = [harry,draco,ron,hermione,dumbledore,hagrid]

But maybe we would like the list to be ordered. We can achieve this with the following query:

setof(X,Y ^ age(X,Y),Out).

(Note that, just like withbagof, we have to tell setof not to generate separate lists for each value of Y, and again we do this with the ^ symbol.)

This query yields:

X = _8711  
Y = _8715  
Out = [draco,dumbledore,hagrid,harry,hermione,ron]

Note that the list is alphabetically ordered.

Now suppose we are interested in collecting together all the ages which are recorded in the database. Of course, we can do this with the following query:

findall(Y,age(X,Y),Out).
 
Y = _8847  
X = _8851  
Out = [13,14,13,13,60,30] 

But this output is rather messy. It is unordered and contains repetitions. By using setof we get the same information in a nicer form:

setof(Y,X ^ age(X,Y),Out).
 
Y = _8981  
X = _8985  
Out = [13,14,30,60] 

Between them, these three predicates offer us a lot of flexibility. For many purposes, all we need is findall. But if we need more, bagof and setof are there waiting to help us out.


Patrick Blackburn, Johan Bos and Kristina Striegnitz
Version 1.2.5 (20030212)