我知道如何在Prolog中找到特定元素的索引,但有没有办法找到大于say X
的数字的第一个实例的索引。例如,假设我有一个列表,但是列表中的某个地方有一个大于1的随机数。我怎样才能找到大于1
的数字的第一个实例的索引?我对Prolog很陌生,并且对谓词的子目标不太擅长。
答案 0 :(得分:5)
您希望在列表 索引和值之间编写关系。我们称之为list_1stindex_gt / 3。有第四个参数来跟踪当前指数是恰当的。但是,不用这个累加器来打扰用户会很好,所以你可以使用辅助谓词和当前索引的附加参数,让它称之为list_1stindex_gt_ / 4。假设您要开始计算1
处的索引(否则将第四个参数更改为0
),您可以像这样定义list_1stindex_gt / 3:
:-use_module(library(clpfd)).
list_1stindex_gt(L,I,GT) :-
list_1stindex_gt_(L,I,GT,1).
对于list_1stindex_gt_ / 4,您有两种情况:
列表的头部大于第三个参数:然后您知道所需的索引。
列表的头部小于或等于第三个参数:然后您将累加器增加1
并继续搜索列表的尾部。
你可以像这样在Prolog中写一下:
list_1stindex_gt_([X|Xs],I,GT,I) :- % case 1
X #> GT.
list_1stindex_gt_([X|Xs],I,GT,Acc0) :- % case 2
X #=< GT,
Acc1 #= Acc0+1,
list_1stindex_gt_(Xs,I,GT,Acc1).
示例查询:哪个索引是给定列表中第一个大于1的元素?
?- list_1stindex_gt([1,1,1,1,5,1,1,2],I,1).
I = 5 ? ;
no
第一个元素大于1的索引在三个变量的列表中?
?- list_1stindex_gt([A,B,C],I,1).
I = 1,
A in 2..sup ? ;
I = 2,
A in inf..1,
B in 2..sup ? ;
I = 3,
A in inf..1,
B in inf..1,
C in 2..sup ? ;
no
第一个元素大于变量X
的哪个索引可以在三个变量的列表中?
?- list_1stindex_gt([A,B,C],I,X).
I = 1,
X#=<A+ -1 ? ;
I = 2,
X#>=A,
X#=<B+ -1 ? ;
I = 3,
X#>=A,
X#=<C+ -1,
X#>=B ? ;
no
此外,您可以考虑@ mat的建议从this answer到之前的问题的改进:遵循(#<)/3背后的想法,您可以定义(#&gt;)/ 3然后使用if_/3定义list_1stindex_gt_ / 4,如下所示:
:-use_module(library(clpfd)).
#>(X, Y, T) :-
zcompare(C, X, Y),
greater_true(C, T).
greater_true(<, false).
greater_true(>, true).
greater_true(=, false).
list_1stindex_gt(L,I,GT) :-
list_1stindex_gt_(L,I,GT,1).
list_1stindex_gt_([X|Xs],I,GT,Acc0) :-
if_(X #> GT,
(I #= Acc0),
(Acc1 #= Acc0+1, list_1stindex_gt_(Xs,I,GT,Acc1))).
这样第一个查询就会成功,而不会打开不必要的选择点:
?- list_1stindex_gt([1,1,1,1,5,1,1,2],I,1).
I = 5.
答案 1 :(得分:4)
这是一个略有不同的看法:
:- use_module(library(clpfd)). :- use_module(library(lists)). :- asserta(clpfd:full_answer). zs_first_greater(Zs, Index, Pivot) :- append(Prefix, [E|_], Zs), maplist(#>=(Pivot), Prefix), E #> Pivot, length([_|Prefix], Index). % 1-based index
使用SICStus Prolog 4.3.3的示例查询:
| ?- zs_first_greater([1,1,1,2,1,1], I, 1).
I = 4 ? ;
no
| ?- zs_first_greater([1,1,1,2,1,1], I, 3).
no
| ?- zs_first_greater([], I, 3).
no
| ?- zs_first_greater([1,1,1,1,5,1,1,2], I, 1).
I = 5 ? ;
no
感谢clpfd,我们也可以提出非常一般的问题:
| ?- zs_first_greater([A,B,C,D], I, X).
I = 1,
A#>=X+1,
A in inf..sup,
X in inf..sup ? ;
I = 2,
A#=<X,
B#>=X+1,
A in inf..sup,
X in inf..sup,
B in inf..sup ? ;
I = 3,
A#=<X,
B#=<X,
C#>=X+1,
A in inf..sup,
X in inf..sup,
B in inf..sup,
C in inf..sup ? ;
I = 4,
A#=<X,
B#=<X,
C#=<X,
D#>=X+1,
A in inf..sup,
X in inf..sup,
B in inf..sup,
C in inf..sup,
D in inf..sup ? ;
no
答案 2 :(得分:1)
要获得L中的任何索引,保持元素V大于N,您可以写:
?- L=[1,2,3,1,2,3],N=2, nth1(I,L,V),V>N.
并限制为第一个实例:
?- L=[1,2,3,1,2,3],N=2, once((nth1(I,L,V),V>N)).
如果您有库(clpfd)可用,并且您的列表的域限制为整数,则元素/ 3可以扮演与nth1 / 3相同的角色,从而提供更多的通用性
答案 3 :(得分:0)
这是一个解决方案,正如其他人指出的那样,它不是通用的,只有当整数列表和阈值是基础术语时它才会起作用。
与大多数列表处理谓词一样,我们需要递归地思考它:
如果你想要元素的索引(而不是它的实际值),我们还需要跟踪索引并在步骤2中增加它。为此,我们需要一个辅助谓词。
%
% Predicate called by the user:
%
% The element of List at Index is the first one greater than Threshold.
%
idx_first_greater(List, Threshold, Index) :-
% here we use our helper predicate, initializing the index at 1.
idx_first_greater_rec(List, Threshold, 1, Index).
%
% Helper predicate:
%
% idx_first_greater_rec(List, Threshold, CurIdx, FoundIdx) :
% The element of List at FoundIndex is the first one greater
% than Threshold. FoundIdx is relative to CurIdx.
%
% Base case. If the header is greater than the Threshold then we are done.
% FoundIdx will be unified with CurIdx and returned back to the recursion stack.
idx_first_greater_rec([H|_], Threshold, Index, Index) :- H > Threshold, !.
% Recursion. Otherwise increment CurIdx and search in the tail of the list
idx_first_greater_rec([_|T], Threshold, CurIdx, FoundIdx) :-
NewIdx is CurIdx+1,
idx_first_greater_rec(T, Threshold, NewIdx, FoundIdx).
注意:
示例输出:
?- idx_first_greater([1,1,1,2,1,1], 1, Idx).
Idx = 4 ;
false.
?- idx_first_greater([1,1,1,2,1,1], 3, Idx).
false.
?- idx_first_greater([], 3, Idx).
false.