2012-10-19 55 views
4

名單我很新的序言,我需要一些幫助,一個小問題:拆分在序言

我想在兩個列表分割的夫妻列表。第一個列表包含所有具有給定鍵的對,第二個列表包含所有其他對象。

這是我的代碼至今:

splitList([],_,[],[]). 
splitList([(A,X)|Rest], B, [Elem1|List1], [Elem2|List2]):- 
    (
     A == B 
    -> 
     Elem1 = (A,X), 
     splitList(Rest, B, List1, [Elem2|List2]) 
    ; 
     Elem2 = (A,X), 
     splitList(Rest, B, [Elem1|List1], List2) 
    ). 

當我嘗試測試它,這就是我得到:

[trace] [3] 143 ?- splitList([(1,yellow),(1,blue),(2,yellow),(2,blue)],1,X,Y). 
    Call: (37) splitList([ (1, yellow), (1, blue), (2, yellow), (2, blue)], 1, _G4821, _G4822) ? creep 
    Call: (38) 1==1 ? creep 
    Exit: (38) 1==1 ? creep 
    Call: (38) _G4928= (1, yellow) ? creep 
    Exit: (38) (1, yellow)= (1, yellow) ? creep 
    Call: (38) splitList([ (1, blue), (2, yellow), (2, blue)], 1, _G4929, [_G4931|_G4932]) ? creep 
    Call: (39) 1==1 ? creep 
    Exit: (39) 1==1 ? creep 
    Call: (39) _G4940= (1, blue) ? creep 
    Exit: (39) (1, blue)= (1, blue) ? creep 
    Call: (39) splitList([ (2, yellow), (2, blue)], 1, _G4941, [_G4931|_G4932]) ? creep 
    Call: (40) 2==1 ? creep 
    Fail: (40) 2==1 ? creep 
    Call: (40) _G4931= (2, yellow) ? creep 
    Exit: (40) (2, yellow)= (2, yellow) ? creep 
    Call: (40) splitList([ (2, blue)], 1, [_G4949|_G4950], _G4932) ? creep 
    Call: (41) 2==1 ? creep 
    Fail: (41) 2==1 ? creep 
    Call: (41) _G4958= (2, blue) ? creep 
    Exit: (41) (2, blue)= (2, blue) ? creep 
    Call: (41) splitList([], 1, [_G4949|_G4950], _G4959) ? creep 
    Fail: (41) splitList([], 1, [_G4949|_G4950], _G4959) ? creep 
    Fail: (40) splitList([ (2, blue)], 1, [_G4949|_G4950], _G4932) ? creep 
    Fail: (39) splitList([ (2, yellow), (2, blue)], 1, _G4941, [_G4931|_G4932]) ? creep 
    Fail: (38) splitList([ (1, blue), (2, yellow), (2, blue)], 1, _G4929, [_G4931|_G4932]) ? creep 
    Fail: (37) splitList([ (1, yellow), (1, blue), (2, yellow), (2, blue)], 1, _G4821, _G4822) ? creep 
false. 

明顯的解決辦法應該是X = [(1 ,黃色),(1,藍色)]和Y = [(2,黃色),(2,藍色)],但我得到了錯誤。 有人能告訴我我做錯了什麼嗎?

由於提前,

WALLE

回答

6

讓我們看一下倒數第二遞歸調用:

splitList([(2,blue)], 1, [Elem1|List1], [Elem2|List2]) 
          ^^^^^^^^^^^ 

在我打上你預計第一批名單的地方至少還有一個元素。但是最後的遞歸調用不能滿足這個條件。這就是它失敗的原因。您的跟蹤的相關部分是:

# penultimate call: 
Call: (40) splitList([ (2, blue)], 1, [_G4949|_G4950], _G4932) ? creep 
[…] 
# last call: 
Call: (41) splitList([], 1, [_G4949|_G4950], _G4959) ? creep 
Fail: (41) splitList([], 1, [_G4949|_G4950], _G4959) ? creep 

沒有替換,將允許_G4949變量在最後一次通話存在。

我會寫這樣說:

splitList([], _, [], []). 
splitList([(A, X)|Rest], A, [(A, X)|Rest1], Rest2) :- 
     splitList(Rest, A, Rest1, Rest2). 
splitList([(A, X)|Rest], B, Rest1, [(A, X)|Rest2]) :- 
     A =\= B, 
     splitList(Rest, B, Rest1, Rest2). 

BTW,精心問的問題!

+0

謝謝,它現在可行! – Walle

4

的問題是在基礎案例。 任取兩案在身:

splitList(Rest, B, List1, [Elem2|List2]) 

當你到最後一切都正確結合,除了最後一個參數,即Rest=[], B=_, List1=[] ......但[Elem2|List2][]統一。

所以程序失敗。

嘗試這樣的事情(我還沒有運行):

splitList([],_,[],[]). 
splitList([(A,X)|Rest], A, [(A,X)|List1], List2):- ! 
     splitList(Rest, A, List1, List2). 
splitList([(B,X)|Rest], A, List1, [(B,X) | List2]):- 
     splitList(Rest, A, List1, List2). 
+0

你在'!'後面寫了一個',',但代碼有效。謝謝! – Walle

1

無需擔心編寫遞歸代碼(以及關於如何正確輸入)!

我們定義splitList/4如下(使用tpartition/4lambdas(=)/3):

:- use_module(library(lambda)). 

splitList(KVs,K,Hits,Misses) :- 
    tpartition(K+\(K0,_)^(K0=K),KVs,Hits,Misses). 

樣品查詢:

 
?- splitList([(1,yellow),(2,green),(1,blue),(2,red)],1,Hits,Misses). 
Hits = [(1,yellow),(1,blue)], Misses = [(2,green),(2,red)]. % deterministic 

怎麼樣東西莉兒位更普遍?

 
?- splitList([(1,yellow),(2,green),(1,blue),(2,red)],K,Hits,Misses). 
     K=1 ,   Hits = [(1,yellow),(1,blue)], Misses = [(2, green),(2, red)] 
;    K=2 , Hits = [(2, green),(2, red)], Misses = [(1,yellow),(1,blue)] 
; dif(K,1), dif(K,2), Hits = []     , Misses = [(1,yellow),(1,blue), 
                   (2, green),(2, red)].