2016-05-12 87 views
1

數據:如何在prolog中只顯示一個結果?

%flight(FID, Start, Destination, Company, Seats). 
%------------------------------------------------------ 
flight(1, 'Paris', 'Berlin', 'Lufthansa', 210). 
flight(2, 'Frankfurt', 'Dubai', 'Lufthansa', 400). 
flight(3, 'Rome', 'Barcelona', 'Eurowings', 350). 

我想知道,有超過200個座位的航班的所有公司。但每家公司只能退回一次。

我想:

q1(Company) :- flight(_, _, _, Company, S), S > 200. 

但這返回德國漢莎航空公司的兩倍。我嘗試過:

q1(Company) :- flight(_, _, _, Company, S), S > 200,!. 

但是,這首先返回漢莎航空後退出。我想我必須包裝在一個子查詢條件:

q1(Company) :- flight(_, _, _, Company, S), q12(S). 
q12(S) :- flight(_, _, _, _, S), S > 200,!. 

但是,這退出後第一次返回,也。任何想法如何我可以退回一個公司只匹配一次使用剪切?

FID是主鍵,我只允許使用。 ,+ <> < => =

+2

首先,刪除'!/ 0':它破壞了程序的預期含義。然後收集所有使用'setof/3'的公司,像這樣:'? - setof(Company,q1(Company),Cs)。「這給你一個沒有重複的排序列表。如果你願意,你可以用'? - setof(C,q1(C),Cs),成員(C,Cs)來枚舉公司。' – mat

+0

@mat我不允許使用setof,只是「,。 !\ + < ><= > =「 –

+2

這是一個奇怪的要求。你能至少使用'sort/2'嗎?否則,你需要在SQL左連接或類似的東西的精神下做一個奇怪的詭計。 – 2016-05-12 12:36:43

回答

2

這裏的關鍵是唯一的ID。您原來的問題是:

哪些公司有超過200個座位的航班?

查詢是顯而易見的:

?- flight(_,_,_,C,S), S > 200. 
C = 'Lufthansa', 
S = 210 ; 
C = 'Lufthansa', 
S = 400 ; 
C = 'Eurowings', 
S = 350. 

現在,因爲ID都是唯一的,也將是該組中的飛行與同一家公司,並具有座位> 200最高(或最低)ID。因此,您可以將您的問題重新制定爲:

哪些航班有200多個座位,並且來自同一家公司的航班組中的最高ID?

,或者做出是否有點更貼近我們可以提出在Prolog的查詢方式,

給出一個ID,公司和座位飛行,座位一定要多超過200,並且不得有同一家公司擁有更高ID的其他航班。

?- flight(ID,_,_,C,S), S > 200, \+ (flight(IDX,_,_,C,_), IDX > ID). 
ID = 2, 
C = 'Lufthansa', 
S = 400 ; 
ID = 3, 
C = 'Eurowings', 
S = 350. 

如果你把這個查詢謂詞中就可以避免報告ID和座位的實際數量。

順便說一句,這種方法是由this answer禮貌的一個有些相關的問題(無恥的自我推銷)。我真的不記得我的想法在哪裏:我確信我沒有自己想出來。如果任何人都可以在這裏找到一個很好的參考Stackoverflow或其他地方請評論。

+0

謝謝你給我帶來了正確的軌道。順便說一句,我發現另一個解決方案,似乎正確使用cut操作符。我把它寫在我的問題上。 –

+0

@artworkadシ你確定你需要那個剪輯嗎?如果你刪除它會發生什麼? – 2016-05-12 14:36:34

+0

是的,否則會有dups –

3

正如我在評論說,要做到這一點的一種方式是使用setof/3以獲得結果而不 複製的排序列表,例如:

?- setof(C, q1(C), Cs). 

這是一個推薦方法來刪除冗餘解決方案。你可以列舉這樣的解決方案,例如有:

?- setof(C, q1(C), Cs), member(C, Cs). 

查看器自由裁量權,建議爲剩餘...


也有幾種方法可以解決這個問題,以腦損傷條件一個不熟練的教練可能會對你施加壓力。例如,下面是獲得所有 公司發生在你的數據庫低效和高非慣用的方式,而不使用setof/3

 
companies(Cs) :- 
    companies_([], Cs). 

companies_(Cs0, Cs) :- 
    ( flight(_, _, _, C, _), 
     \+ memberchk(C, Cs0) -> 
     companies_([C|Cs0], Cs) 
    ; Cs0 = Cs 
    ). 

我沒有胃進一步落實這一點,所以我只是爲你提示:你只需要插入一個目標來解決你的任務。我希望你的老師對這個「解決方案」感到滿意。

+2

這使用'memberchk/2',這可能也不是「允許」:)但請參閱另一種方法的其他答案。 – 2016-05-12 13:54:06

+3

此版本中的所有內容都可以使用僅顯示的基元輕鬆表示。例如,'memberchk/2'和if-then-else可以用'!/ 0'表示。這些都是邏輯*黑客*,而不是邏輯*編程*的例子,所以我不想在這個方向上展現更多。 – mat

+0

爲什麼'memberchk/2'呢? – false