Как я могу отфильтровать список по 2 условиям?

Я новичок в прологе и не могу найти решение отфильтровать список по 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)

Особенно я не понимаю, как работать с двумя переменными одновременно.

Учебная записка [Medium] Leetcode#22 Generate Parentheses
Учебная записка [Medium] Leetcode#22 Generate Parentheses
На этот раз мы собираемся решить еще одну классическую проблему, связанную с парными скобками, так называемую генерацию скобок.
0
0
55
5
Перейти к ответу Данный вопрос помечен как решенный

Ответы 5

Самый простой способ — использовать рабочий предикат, несущий требуемое дополнительное состояние.

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.

Если вы maplistsignэто над входами:

?- 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] 

Другие вопросы по теме