Given some list of integers, I want to calculate the sum of every second element in the list using Prolog ?
E.g.:
[1,2,3,4] => [2+4] = 6
Given some list of integers, I want to calculate the sum of every second element in the list using Prolog ?
E.g.:
[1,2,3,4] => [2+4] = 6
There are several ways to accomplish this, but to give you an idea of a simple recursive solution using an accumulator to keep track of the current sum:
% Sets accumulator to 0 for convenience
sum_second(List,Result) :- sum_second(List,0,Result).
sum_second([],A,A). % Empty list
sum_second([_],A,A). % One element left in list
sum_second([_,H|T],A,R) :- % Accumulate sum of second element
A2 is A+H,
sum_second(T,A2,R).
Example usage:
?- sum_second([1],R).
R = 0.
?- sum_second([1,2],R).
R = 2.
?- sum_second([1,2,3,4,5,6],R).
R = 12.
While the solution by @SeekAndDestroy is okay, I'd like to add:
Use clpfd for declarative integer arithmetics.
:- use_module(library(clpfd)).
Employ first-argument indexing to avoid useless choicepoints.
list_evens_odds([], [], []). list_evens_odds([X|Xs], [X|Es], Os) :- list_evens_odds(Xs, Os, Es).
That's it!
To sum up every other item (starting with the 2nd), query like so:
?- list_evens_odds([1,2,3,4], _, Zs), sum(Zs, #=, Sum). Zs = [2,4], Sum = 6.
I would use library(aggregate):
sum_every_nth1(L,I,S) :- aggregate(sum(X), P^(nth1(P,L,X), P mod I=:=0), S).
?- sum_every_nth1([1,2,3,4],2,S).
S = 6.
sum_every_nth1/3 is based on the 'relational' behaviour of nth1/3, that binds a position (P in the sample) in a list to an element. So, when called with P free, it binds it to successive indexes. The goal P mod I=:=0
then filters out the indexes not satisfying the requirement (cause failure of the conjunction - a comma means AND).
edit
library(aggregate) has a specific purpose, namely to supply missing aggregation operators available in SQL. To handle multiplication, I would suggest to separate the 'fetching' of elements from the actual operation performed on them:
every_nth1(L,I,Ns) :- findall(X, (nth1(P,L,X),P mod I=:=0), Ns).
mul_every_nth1(L,I,M) :-
every_nth1(L,I,[N0|Ns]),
foldl([N,M0,M1]>>(M1 is M0*N),Ns,N0,M).
every_nth1/3 get a list of selected elements, foldl/4 takes care to multiply them.
?- mul_every_nth1([1,2,3,4],2,M).
M = 8.
edit
if you're missing library(yall):
multiply(N,M0,M1) :- M1 is M0*N.
mul_every_nth1(L,I,M) :-
every_nth1(L,I,[N0|Ns]),
foldl(multiply,Ns,N0,M).