2011-03-03 148 views
8

我正在嘗試Prolog第一次,並有使用名單有點困難。序言 - 如何檢查列表是否包含某些元素?

說我有一個元素列表。我要檢查,該列表包含以下元素:

所有:A1,A2,A3,A4,A5

之一:B1,B2,B3,B4

兩個:C1 ,C2,C3,C4,C5,C6

例如,[A1,A2,B2,C1,A3,A4,C4,A5]滿足要求和[A2,A1,C1,B1,A3,A4 ] 纔不是。

我該如何寫出如果列表符合要求則返回Yes/True,否則返回No/False?同樣,如何編寫一些從列表中返回所需的滿足要求的缺失值?

回答

18

你問了很多問題!讓我讓你開始解決大部分需求的謂詞。

首先,讓我們來解決檢查一個列表的所有項目也都在其他名單的情況:

subset([ ],_). 
subset([H|T],List) :- 
    member(H,List), 
    subset(T,List). 

這簡單而又重複利用熟悉的成員/ 2謂詞來驗證每個條目中子集/ 2的第一個參數指定的列表也位於由第二個參數指定的列表中。 [爲了簡單起見,我假定這些列表的條目是不同的。如果我們想驗證第一個列表的一個條目的多個實例與第二個列表中的至少多個實例相匹配,則需要更詳細的版本。]

好吧,如何檢查(至少)第一個列表中的一個也屬於第二個列表?顯然這是一個不同於上面的謂詞。如果存在第一個列表中屬於第二個列表的任何一個項目,而不是所有項目在第一個列表中,則目標將被滿足。

intersects([H|_],List) :- 
    member(H,List), 
    !. 
intersects([_|T],List) :- 
    intersects(T,List). 

此遞歸失敗如果達到了第一個參數的空列表,但在此之前,所述第一列表中的一個成員,發現屬於第二列表的任何一點,如果成功。 [即使一個項目的多個實例出現在任何一個列表中,該謂詞也可以正常工作。然而,如果我們想要檢查恰好一個第一個列表的項目屬於第二個列表,那麼需要改進邏輯,並且這將需要擔心多個實例是否與確切的計數一致或與計數一致。]

如果我們想概括此檢查,以驗證(至少)第一個列表中的N項是否在第二個列表中,該怎麼辦?生成的謂詞將需要第三個參數:

intersectsAtLeast(_,_,N) :- N <= 0, !. 
intersectsAtLeast([H|T],L,N) :- 
    member(H,L), 
    !, 
    M is N-1, 
    intersectsAtLeast(T,L,M). 
intersectsAtLeast([_|T],L,N) :- 
    intersectsAtLeast(T,L,N). 

這個遞歸致力於通過列表中,由一個每個第一清單上的項目原來是在第二個列表以及時間遞減的第三個參數,併成功一旦計數減少到0(或更少)。 [如果列表可以重複,這裏的代碼需要更多的工作。]

最後,你要求寫一些「返回缺失值」的東西來滿足需求。這在檢查兩個列表中的一個或多個項目的情況下沒有明確定義,因爲「缺失值」可能是許多可能項目中的任何一個。在我們要求第一個列表中的所有項目屬於第二個列表的特殊情況下,可以確定「缺失值」(如果有的話)。

missingValues([ ],_,[ ]). 
missingValues([H|T],L,K) :- 
    member(H,L), 
    !, 
    missingValues(T,L,K). 
missingValues([H|T],L,[H|K]) :- 
    missingValues(T,L,K). 

這裏遞歸「動作」的項目從輸入第一個列表輸出「缺項」第三個列表,當且僅當它們不會出現在第二個列表。

關於您的問題的最後一個注意事項涉及符號。在Prolog中,變量是以大寫字母或下劃線開頭的標識符,所以如果列表中的項目被用作「未知數」而不是(正如我假定你的意思)不同的原子(常量)。切換到小寫字母可以解決這個問題。

相關問題