2011-04-10 106 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不支持这种语法。