Я новичок в прологе и не могу найти решение отфильтровать список по 2 условиям, сохранить результат в 2 переменные и затем оценить на основе ответов.
В моем случае, если список содержит больше чисел больше 0, то числа меньше 0.
Например, я получаю список с элементами:
checklist([-2, 3.3, 12, -10.1, 14, -11, 123]) # true
checklist([-2.1, -3, -4, 14, 16.7]) # false
checklist([11.5, 2.5, -34.1, -1]) # false
Я бы написал что-то вроде этого на питоне:
bigger_count = 0
lesser_count = 0
for num in list:
if num > 0:
bigger_count += 1
elif num < 0:
lesser_count += 1
print(bigger_count > lesser_count)
Особенно я не понимаю, как работать с двумя переменными одновременно.
Самый простой способ — использовать рабочий предикат, несущий требуемое дополнительное состояние.
checklist( Ns, P, N ) :- checklist(Ns, 0, 0, P, N )
checklist( [] , P , N , P , N ) .
checklist( [X|Xs] , P0 , N0 , P , N ) :- X > 0, P1 is P0+1, checklist(Xs,P1,N0,P,N).
checklist( [X|Xs] , P0 , N0 , P , N ) :- X < 0, B1 is N0+1, checklist(Xs,P0,N1,P,N).
Другое возможное решение:
check(List) :-
check(List, Balance),
Balance > 0.
check([], 0).
check([X|Xs], B) :-
check(Xs, B0),
( X > 0 -> B is B0 + 1
; X < 0 -> B is B0 - 1
; B is B0 ).
Примеры:
?- check([-2, 3.3, 12, -10.1, 14, -11, 123]).
true.
?- check([-2.1, -3, -4, 14, 16.7]).
false.
?- check([11.5, 2.5, -34.1, -1]).
false.
?- check([1,-1]).
false.
Если вы сложите все значения в списке, вы получите положительный или отрицательный результат, который зависит от того, насколько велики числа, а не от их количества. Существует математическая функция sign
или signum
, которая превращает все отрицательные значения в -1, а все положительные значения в +1, затем вы можете их сложить, и если было больше положительных входов, ответ положительный, если отрицательных входов больше , ответ отрицательный. Или они сойдутся, и сумма будет равна 0.
Если вы maplist
sign
это над входами:
?- maplist(sign, [-2, 3.3, 12, -10.1, 14, -11, 123], X).
X = [-1, 1.0, 1, -1.0, 1, -1, 1]
Затем:
?- sum_list(X, S).
S = 1.0
положительный результат, так что больше положительных, чем отрицательных в этом случае.
вы можете partition/4
ввести список в меньшие и большие значения:
?- partition(>(0), [-2, 3.3, 12, -10.1, 14, -11, 123], Lesser, Greater).
Lesser = [-2, -10.1, -11],
Greater = [3.3, 12, 14, 123]
Затем используйте length/2
и сравните результат, чтобы увидеть, какой из них длиннее.
(Это может быть бесполезно, если какие-либо входные данные 0
, их нет в ваших примерах. Я думаю, что это потребует больше памяти для создания копии списка.).
https://www.swi-prolog.org/pldoc/doc_for?object=include/3
https://www.swi-prolog.org/pldoc/doc_for?object=convlist/3
Если у вас есть 2 условия, вам нужно пройти по списку дважды, но стоит ли сложность кода, который может обрабатывать два разных предиката?
В любом случае, если вы пишете с нуля, вы можете упростить себе жизнь, используя DCG:
filter(_Pred, []) --> [].
filter(Pred, [X|Xs]) -->
( { call(Pred, X) }
-> [X]
; []
),
filter(Pred, Xs).
filter(Pred, List, Result) :-
phrase(filter(Pred, List), Result).
even(X) :- 0 is X mod 2.
?- filter(even, [1,2,3,4,5], X).
X = [2, 4]