3

I have a list of numbers, I need to calculate the sum of the even numbers of the list and the product of the odd numbers of the same list. I'm new in Prolog, and my searches so far weren't successful. Can anyone help me solve it ?

l_odd_even([]). 
l_odd_even([H|T], Odd, [H|Etail]) :-
    H rem 2 =:=0,
    split(T, Odd, Etail). 
l_odd_even([H|T], [H|Otail], Even) :-
    H rem 2 =:=1,
    split(T, Otail, Even).
repeat
  • 18,496
  • 4
  • 54
  • 166
Rares
  • 33
  • 1
  • 4
  • Can you show what you've already tried? – Steve Vinoski Sep 12 '15 at 21:25
  • First, you need to make an attempt. I understand you're new to Prolog, but what have you learned so far about Prolog? Since you're dealing with *a list of numbers* you'll want to manipulate a list. You can Google "prolog list processing" and get some good information on how to manage lists. For starters, `[]` is the empty list, and `[H|T]` is a list with first element `H` and *rest* of the list (the *tail*) is `T`. – lurker Sep 12 '15 at 21:27
  • well this is my code so far "l_odd_even([]). l_odd_even([H|T], Odd, [H|Etail]) :- ((H rem 2)=:=0), split(T, Odd, Etail). l_odd_even([H|T], [H|Otail], Even) :- ((H rem 2)=:=1), split(T, Otail, Even)." I just don't know hot to implement the sum and the product after this – Rares Sep 12 '15 at 21:57

4 Answers4

2

Here is a suggestion for the sum of the even numbers from a list:

even(X) :- 
  Y is mod(X,2),       % using "is" to evaluate to number
  Y =:= 0.

odd(X) :-              % using even
  Y is X + 1,
  even(Y).

sum_even(0, []).       % empty list has zero sum
sum_even(X, [H|T]) :- 
  even(H),
  sum_even(Y, T), 
  X is Y+H.
sum_even(X, [H|T]) :- 
  odd(H),
  sum_even(X, T).      % ignore the odd numbers

Note: My Prolog has oxidized, so there might be better solutions. :-)

Note: Holy cow! There seems to be no Prolog support for syntax highlighting (see here), so I used Erlang syntax. Ha, it really works. :-)

Running some queries in GNU Prolog, I get:

| ?- sum_even(X,[]).    
X = 0 ?     
yes

| ?- sum_even(X,[2]).   
X = 2 ? 
yes

| ?- sum_even(X,[3]).    
X = 0 ? 
yes

| ?- sum_even(X,[5,4,3,2,1,0]).    
X = 6 ? 
yes

The ideas applied here should enable you to come up with the needed product.

Community
  • 1
  • 1
mvw
  • 5,075
  • 1
  • 28
  • 34
2

Use !

:- use_module(library(clpfd)).

Building on foldl/4, we only need to define what a single folding step is:

sumprod_(Z,S0,S) :-
   M #= Z mod 2,
   rem_sumprod_(M,Z,S0,S).

rem_sumprod_(0,Z,S0-P,S-P) :- 
   S0 + Z #= S.
rem_sumprod_(1,Z,S-P0,S-P) :- 
   P0 * Z #= P.

Let's fold sumprod_/3 over the list!

l_odd_even(Zs,ProductOfOdds,SumOfEvens) :-
   foldl(sumprod_,Zs,0-1,SumOfEvens-ProductOfOdds).

Sample query:

?- l_odd_even([1,2,3,4,5,6,7],Odd,Even).
Odd = 105,
Even = 12.

Alternatively, we can define sumprod_/3 even more concisely by using if_/3 and zeven_t/3:

sumprod_(Z,S0-P0,S-P) :-
   if_(zeven_t(Z), (S0+Z #= S, P0=P),
                   (P0*Z #= P, S0=S)).
Community
  • 1
  • 1
repeat
  • 18,496
  • 4
  • 54
  • 166
1

untested!

sum_odd_product_even([], S, P, S, P).
sum_odd_product_even([H|T], S0, P0, S, P) :-
    S1 is S0 + H,
    sum_even_product_odd(T, S1, P0, S, P).

sum_even_product_odd([], S, P, S, P).
sum_even_product_odd([H|T], S0, P0, S, P) :-
    P1 is P0 * H,
    sum_odd_product_even(T, S0, P1, S, P).

sum_odd_product_even(L, S, P) :-
    sum_odd_product_even(L, 0, 1, S, P).

sum_even_product_odd(L, S, P) :-
    sum_even_product_odd(L, 0, 1, S, P).
salva
  • 9,943
  • 4
  • 29
  • 57
  • 1
    So, the product of nothing is 1? –  Sep 14 '15 at 06:13
  • 2
    @Boris: yes, the neutral element of multiplication. – salva Sep 14 '15 at 06:16
  • 1
    I am not sure, but I _think_ that what you are sort of getting at is the sum and product of numbers at even and odd _positions_, but it seems that OP is trying to get the sum and product of even and odd _numbers_. –  Sep 14 '15 at 06:33
0

It shouldn't get much simpler than

%
% invoke the worker predicate with the accumulators seeded appropriately.
%
odds_and_evens( [O]      , P , S ) :- odds_and_evens( [] , O , 0 , P , S ) .
odds_and_evens( [O,E|Ns] , P , S ) :- odds_and_evens( Ns , O , E , P , S ) .

odds_and_evens( []       , P , S , P , S  ) . % if the list is exhausted, we're done.
odds_and_evens( [O]      , X , X , P , S ) :- % if it's a single element list, we've only an odd element...
  P is X*O ,                                  % - compute it's product
  .                                           % - and we're done.
odds_and_evens( [O,E|Ns] , X , Y , P , S ) :- % if the list is at least two elements in length'e both an odd and an even:
  X1 is X*O ,                                 % - increment the odd accumulator
  Y1 is Y+E ,                                 % - increment the even accumulator
  odds_and_evens( Ns , X1 , Y1 , P , S )      % - recurse down (until it coalesces into one of the two special cases)
  .                                           % Easy!
Nicholas Carey
  • 71,308
  • 16
  • 93
  • 135