This is a problem suma( [ [ 1, 2, 3, 4 ], [ 2, 3, 4, 5 ], [ 3, 4, 5, 6 ] ], X ), and i need to get this result X = [ 10, 14, 18 ]. I don't have any idea how to figure this out. Please help
This is a problem suma( [ [ 1, 2, 3, 4 ], [ 2, 3, 4, 5 ], [ 3, 4, 5, 6 ] ], X ), and i need to get this result X = [ 10, 14, 18 ]. I don't have any idea how to figure this out. Please help
maplist/3 and foldl/4 and yall notation (the last one available in SWI-Prolog) are your friends.
suma(ListOfLists,ListOfSums) :-
maplist(
([Sublist,Sum]>>
(foldl(
[AccumIn,X,AccOut]>>(AccOut is AccumIn + X),
Sublist,
0,
Sum))),
ListOfLists,
ListOfSums).
Thus:
?- suma( [ [ 1, 2, 3, 4 ], [ 2, 3, 4, 5 ], [ 3, 4, 5, 6 ] ], X ).
X = [10, 14, 18].
This is less logic programming than functional programming, but if one has a Swiss Army Knife, one might as well use it!
maplist/3: Calls the goal that is on argument position 0 for every pair [Sublist,Sum] where Sublist is an element of the list on argument position 1 (i.e. ListOfLists) and Sum is an element of the list on argument position 2 (i.e. ListOfSums), both elements being at the same position in their respective lists.[Sublist,Sum] and calls foldl/4, which "folds-left" the list Sublist using the goal on argument position 0, starting with value 0 and resulting in value Sum.[AccumIn,X,AccOut]>>(AccOut is AccumIn + X).This can be more extensively written as:
suma(ListOfLists,ListOfSums) :-
maplist(
p2, % will be called with 2 parameters
ListOfLists,
ListOfSums).
p2(Sublist,Sum) :-
foldl(
p3, % will be called with 3 parameters
Sublist,
0,
Sum).
p3(AccumIn,X,AccOut) :-
AccOut is AccumIn + X.
We can run some plunit test cases for good measure (actually, the problem to solve should be stated with the below, TDD and all that):
:- begin_tests(sum_over_sublists).
test("empty list of lists",true(R == [])) :-
suma([],R).
test("all sublists contain one value",true(R == [1,2,3])) :-
suma([[1],[2],[3]],R).
test("one sublist is empty",true(R == [1,0,3])) :-
suma([[1],[],[3]],R).
test("standard case #1",true(R == [6,15,24])) :-
suma([[1,2,3],[4,5,6],[7,8,9]],R).
test("standard case #2",true(R == [10,14,18])) :-
suma([[1,2,3,4],[2,3,4,5],[3,4,5,6]],R).
:- end_tests(sum_over_sublists).
And so:
?- run_tests.
% PL-Unit: sum_over_sublists ..... done
% All 5 tests passed
true.
%! sum(Xs,SUM)
%
% calculate the total sum of the items in list `Xs` .
sum(Xs,SUM)
:-
sum(Xs,0,SUM)
.
sum([],SUM0,SUM0) .
sum([X0|Xs],SUM0,SUM)
:-
SUM1 is SUM0 + X0 ,
sum(Xs,SUM1,SUM)
.
/*
?- sum([1,2,3,4],SUM).
SUM = 10.
?- sum([2,3,4,5],SUM).
SUM = 14.
?- sum([3,4,5,6],SUM).
SUM = 18.
*/
%! suma(Xss0,SUM)
%
% calculate the total sum of the items in list of lists `Xss` .
suma([],0) .
suma([Xs0|Xss0],SUM)
:-
sum(Xs0,SUM0) ,
suma(Xss0,SUM1) ,
SUM is SUM0 + SUM1
.
/*
?- suma([[1,2,3,4],[2,3,4,5]],SUM).
SUM = 24.
?- suma([[1,2,3,4],[2,3,4,5],[3,4,5,6]],SUM).
SUM = 42.
*/