# Count number of occurrence in a list with condition

**URL:** <https://swi-prolog.discourse.group/t/count-number-of-occurrence-in-a-list-with-condition/5646>\
**Category:** Help!\
**Tags:** how-to, list\
**Created:** [August 2, 2022, 4:54pm UTC](https://swi-prolog.discourse.group/t/count-number-of-occurrence-in-a-list-with-condition/5646 "2022-08-02T16:54:27Z")\
**Posts on this page:** 7\
**Page:** 1

<div class="post-metadata">

**Author:** ![elfi](https://avatars.discourse-cdn.com/v4/letter/e/51bf81/32.png) [@elfi](https://swi-prolog.discourse.group/u/elfi)\
**Post date:** [August 2, 2022, 4:54pm UTC](https://swi-prolog.discourse.group/t/count-number-of-occurrence-in-a-list-with-condition/5646/1 "2022-08-02T16:54:27Z")

</div>

I’m using: [SWI-Prolog](https://www.swi-prolog.org/pldoc/doc_for?object=manual) version 8.4.3 for x64-win64

i have a list of predicates :

```prolog
ListP = [
   patient(201, 4, 2, inTime),
   patient(202, 3, 2, late),
   patient(203, 2, 3, late),
   patient(204, 1, 3, late),
   patient(204, 1, 4, inTime),
   patient(203, 2, 4, late),
   patient(204, 1, 5, inTime),
   patient(204, 1, 5, inTime)
].

```

and i want to count number of patients inTime categorized by their 3rd argument:

I want the result to be something like :

```prolog
Occ = [
   [patient(_, _, 2, inTime), 1],
   [patient(_, _, 3, inTime), 0],
   [patient(_, _, 4, inTime), 1],
   [patient(_, _, 5, inTime), 2]
].

```

What i tried :

```prolog
count_occurrences(List, Occ):-
   findall(
      [patient(_,_,X,inTime),L],
      (bagof(true,member(patient(_,_,X,inTime),List),Xs), length(Xs,L)),
      Occ
   ).

```

The result of my code :

```prolog
Occ = [
   [patient(_, _, 2, inTime), 1],
   [patient(_, _, 4, inTime), 1],
   [patient(_, _, 5, inTime), 2]
].

```

it works well except that it does not give me the result for the patient whose 3rd argument is **3**  
`[patient(_, _, 3, inTime), 0]` is omitted.

Thanks for your help

---

<div class="post-metadata">

**Author:** ![brebs](https://avatars.discourse-cdn.com/v4/letter/b/e9c0ed/32.png) [@brebs](https://swi-prolog.discourse.group/u/brebs)\
**Post date:** [August 2, 2022, 6:08pm UTC](https://swi-prolog.discourse.group/t/count-number-of-occurrence-in-a-list-with-condition/5646/2 "2022-08-02T18:08:32Z")

</div>

Use [Sorting predicates in PROLOG - #19 by brebs](https://swi-prolog.discourse.group/t/sorting-predicates-in-prolog/5618/19) and adapt it to count.

---

<div class="post-metadata">

**Author:** ![CapelliC](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/capellic/32/17_2.png) [@CapelliC](https://swi-prolog.discourse.group/u/CapelliC)\
**Post date:** [August 2, 2022, 6:13pm UTC](https://swi-prolog.discourse.group/t/count-number-of-occurrence-in-a-list-with-condition/5646/3 "2022-08-02T18:13:05Z")

</div>

It happens because bagof/3 **fails** if it cannot find any answer (in contrast, findall/3 succeeds with an empty list).  
It’s not easy to fix your code, because you’re using bagof to produce the distinct values. Maybe

```prolog
count_occurrences(ListP,CountInTime) :-
    map_list_to_pairs(arg(3),ListP,Keyed),
    group_pairs_by_key(Keyed,Grouped),
    findall([patient(_,_,K,inTime),N],
            ( member(K-L,Grouped),
                aggregate_all(count,member(patient(_,_,K,inTime),L),N)
            ),CountInTime).

```

---

<div class="post-metadata">

**Author:** ![elfi](https://avatars.discourse-cdn.com/v4/letter/e/51bf81/32.png) [@elfi](https://swi-prolog.discourse.group/u/elfi)\
**Post date:** [August 2, 2022, 6:21pm UTC](https://swi-prolog.discourse.group/t/count-number-of-occurrence-in-a-list-with-condition/5646/4 "2022-08-02T18:21:54Z")

</div>

OMG, Yous saved my life ! Thanks so much.  
̶C̶a̶n̶ ̶i̶ ̶u̶s̶e̶ ̶t̶h̶e̶ ̶s̶a̶m̶e̶ ̶f̶u̶n̶c̶t̶i̶o̶n̶ ̶t̶o̶ ̶c̶o̶u̶n̶t̶ ̶n̶u̶m̶b̶e̶r̶ ̶o̶f̶ ̶p̶r̶e̶d̶i̶c̶a̶t̶e̶s̶,̶ ̶c̶l̶a̶s̶s̶i̶f̶i̶e̶d̶ ̶b̶y̶ ̶t̶h̶e̶i̶r̶ ̶3̶r̶d̶ ̶a̶r̶g̶u̶m̶e̶n̶t̶.̶

̶t̶o̶ ̶g̶e̶t̶ ̶s̶o̶m̶e̶t̶h̶i̶n̶g̶ ̶L̶i̶k̶e̶ ̶:̶

```prolog
Occ = [
   [patient(_, _, 2, _), 2],
   [patient(_, _, 3, _), 2],
   [patient(_, _, 4, _), 2],
   [patient(_, _, 5, _), 2]
].

```

SOLVED :

I just changed the **inTime** in the code to a **\_**

```prolog
count_occurrences_all(ListP,CountInTime) :-
    map_list_to_pairs(arg(3),ListP,Keyed),
    group_pairs_by_key(Keyed,Grouped),
    findall([patient(_,_,K,_),N],
            ( member(K-L,Grouped),
                aggregate_all(count,member(patient(_,_,K,_),L),N)
            ),CountInTime).

```

---

<div class="post-metadata">

**Author:** ![CapelliC](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/capellic/32/17_2.png) [@CapelliC](https://swi-prolog.discourse.group/u/CapelliC)\
**Post date:** [August 2, 2022, 6:54pm UTC](https://swi-prolog.discourse.group/t/count-number-of-occurrence-in-a-list-with-condition/5646/5 "2022-08-02T18:54:51Z")

</div>

If don’t need to discriminate by **inTime** , then could be a bit easier:

```prolog
count_occurrences_all(ListP,Counted) :-
    map_list_to_pairs(arg(3),ListP,Keyed),
    group_pairs_by_key(Keyed,Grouped),
    findall([patient(_,_,K,_),N],
            ( member(K-L,Grouped),
                length(L,N)
            ),Counted).

```

or

```prolog
count_occurrences_all(ListP,Counted) :-
    map_list_to_pairs(arg(3),ListP,Keyed),
    group_pairs_by_key(Keyed,Grouped),
    maplist([K-L,[patient(_,_,K,_),N]]>>length(L,N),Grouped,Counted).

```

Always try to keep the logic as simple as possible…

---

<div class="post-metadata">

**Author:** ![elfi](https://avatars.discourse-cdn.com/v4/letter/e/51bf81/32.png) [@elfi](https://swi-prolog.discourse.group/u/elfi)\
**Post date:** [August 2, 2022, 7:22pm UTC](https://swi-prolog.discourse.group/t/count-number-of-occurrence-in-a-list-with-condition/5646/6 "2022-08-02T19:22:03Z")

</div>

How can i iterate throught both lists so i can make operation between the second element of each sublist :

```prolog
Occ = [
   [patient(_, _, 2, inTime), 1],
   [patient(_, _, 3, inTime), 0],
   [patient(_, _, 4, inTime), 1],
   [patient(_, _, 5, inTime), 2]
].

Occ_all = [
   [patient(_, _, 2, _), 2],
   [patient(_, _, 3, _), 2],
   [patient(_, _, 4, _), 2],
   [patient(_, _, 5, _), 2]
].

```

For exemple division:

```prolog
1/2
0/2
1/2
2/2

```

To get the following list :  
`ResList=[0.5, 0, 0.5, 1].`

---

<div class="post-metadata">

**Author:** ![peter.ludemann](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/peter.ludemann/32/48_2.png) [@peter.ludemann](https://swi-prolog.discourse.group/u/peter.ludemann)\
**Post date:** [August 2, 2022, 10:13pm UTC](https://swi-prolog.discourse.group/t/count-number-of-occurrence-in-a-list-with-condition/5646/7 "2022-08-02T22:13:28Z")

</div>

> [@elfi](#):
>
> How can i iterate throught both lists so i can make operation between the second element of each sublist

maplist/4 … something like this:

```prolog
div([_,X], [_,Y], Z) :- Z is X/2.
?- maplist(div, Occ, Occ_all, Result).

```
