簡體   English   中英

第一個元素的索引大於X(Prolog)

[英]Index of first element greater than X (Prolog)

我知道如何在Prolog中找到特定元素的索引,但有沒有辦法找到大於X的數字的第一個實例的索引。 例如,假設我有一個列表,但是列表中的某個地方有一個大於1的隨機數。 我怎樣才能找到大於1的第一個實例的索引? 我是Prolog的新手,並且不太善於謂詞的子目標。

您希望在列表索引之間編寫關系。 我們稱之為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,你有2個案例:

  1. 列表的頭部大於第三個參數:然后您知道所需的索引。

  2. 列表的頭部小於或等於第三個參數:然后將累加器遞增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建議從你對前一個問題的回答改進:遵循背后的想法(#<)/ 3你可以定義(#>)/ 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.

這是一個略有不同的看法:

:- 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

感謝我們也可以提出非常一般的查詢:

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

要獲得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相同的角色,從而提供更多的通用性

這是一個解決方案,正如其他人指出的那樣,它不是通用的,它只有在整數列表和閾值是基礎術語時才有效。

與大多數列表處理謂詞一樣,我們需要遞歸地考慮它:

  1. 檢查列表的標題(第一個元素)。 如果它大於提供的閾值,那么我們就完成了。
  2. 否則將步驟1應用於列表的尾部(刪除標題后剩余的列表)。

如果你想要元素的索引(而不是它的實際值),我們還需要跟蹤索引並在步驟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).

筆記:

  1. 如果傳遞空列表或者未找到大於閾值的元素,則謂詞將失敗。 這對我來說就像一個好的行為。
  2. 這個解決方案是尾遞歸的,所以它可以由Prolog自動優化。

樣本輸出:

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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM