如何按 2 个条件过滤列表?

How can i filter a list by 2 conditions?

我是 prolog 的新手,我找不到 按 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

我会在python中写这样的东西:

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)

尤其是我不明白如何同时处理 2 个变量。

最简单的方法是使用带有所需额外状态的工作谓词。

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.

如果您将列表中的所有值相加,您将得到一个正数或负数的结果,这取决于数字的大小,而不是数字的数量。有一个数学函数 signsignum 将所有负值变成-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]