2011-04-10 38 views
1

我想將一個列表對轉換爲兩個列表 - 首先包含對的第一個元素,第二個包含對的第二個元素。如何在SWI-Prolog中使用foreach

E.g.

[['Test1', 'US'], ['Test1', 'France'], ['Test2', 'German']] 

應該產生

List1 = ['Test1', 'Test1', 'Test2'] 
List2 = ['US', 'France', 'German'] 

我試圖用foreach並想出這個功能:

testfor:- 
List = [['Test1', 'US'], ['Test1', 'France'], ['Test2', 'German']], 
(
    foreach(X,List) do 
    X=[F,S], 
    append([F],[],List1), 
    append([S],[],List2) 
), 
writeln(List1). 

它不工作,我很困惑。我在哪裏犯了一個錯誤?當然,您可以使用您的方法幫助我實現此功能(即「不要使用foreach」)。

回答

1

yoba([], [], []). 
yoba([[Name1, Name2] | Tail], List1, List2) :- 
    append([Name1], ListNew1, List1), 
    append([Name2], ListNew2, List2), 
    yoba(Tail, ListNew1, ListNew2). 

而且

?- yoba([['Test1', 'US'], ['Test1', 'France'], ['Test2', 'German']], X, Y). 
X = ['Test1', 'Test1', 'Test2'], 
Y = ['US', 'France', 'German']. 
1
pairs_to_lists([], [], []). 

pairs_to_lists([E1-E2 | Tail], [E1 | Tail1], [E2 | Tail2]) :- 
    pairs_to_lists(Tail, Tail1, Tail2). 

用法:

?- pairs_to_lists(['Test1'-'US', 'Test1'-'France', 'Test2'-'German'], L1, L2). 
L1 = ['Test1', 'Test1', 'Test2'], 
L2 = ['US', 'France', 'German']. 

一些評論:

  1. 如果知道列表中的元素數目,列表就是一種矯枉過正的行爲。而不是[A, B]使用A-Bpair(A, B)
  2. append([A], L1, L2)L2 = [A | L1]相同,後者更具可讀性。
0
testfor([], [], []). 
testfor([[X, Y]|T1], [X|T2], [Y|T3]):-testfor(T1, T2, T3). 
1

使用maplist/4,整個迭代是隱藏的,你要想到只是一對的解構。因此

%zip(?FirstList, ?SecondList, ?PairList) 
zip(Fst, Snd, Pair) :- maplist(pair, Fst, Snd, Pair). 

%pair(?First, ?Second, ?Pair) 
pair(Fst, Snd, [Fst, Snd]). 

使用它:

?- zip(List1, List2, [['Test1', 'US'], ['Test1', 'France'], ['Test2', 'German']]). 
List1 = ['Test1', 'Test1', 'Test2'], 
List2 = ['US', 'France', 'German']. 

注意,這是一種先進的解決方案,但。首先,瞭解基本的遞歸解決方案(由其他答案提供)非常有用,我推薦它。如果沒有很好地掌握遞歸,Prolog只是一個大地獄。實際上,maplist也是使用遞歸,它只是從調用者隱藏起來。

另一個要學習的是Prolog術語和統一是如何工作的。

  • 使用append在這裏完全沒有必要。而且,這對性能和可讀性都是有害的。
  • 使用仿函數可以更好地表示對,對['Test1', 'US']變成pair('Test1', 'US')。除了其他好處之外,意外混淆成對和三胞胎更是難上加難。使用函子有點類似於使用其他語言的類型。

    SWI-Prolog使用連字符作爲pairs的函子。由於有operator declaration,連字符也可用於中綴表示法。例如。對['Test1', 'US']變成'Test1'-'US'。中綴符號只是用於其他函數的通用前綴符號的語法糖(即'Test1'-'US' == -('Test1', 'US'))。

最後,你試圖用foreach ... do符號看起來像一個loop construct from ECLiPSe,這是Prolog的派生的語言。 SWI-Prolog不支持這種語法。