序言误解。将列表拆分为两个列表,其中偶数位置和奇数位置。我的错误在哪里?
prolog misunderstanding. Split list into two list with even and odd positions. where is my mistake?
我正在尝试将一个列表拆分为另外两个列表。列出偶数,元素处于偶数位置,列表奇数与其他元素。我一直在网上寻找解决方案,但在我看来都像中文,我无法理解这个过程。所以这就是我一直在尝试的:
split(List,Odd,Even):-odd(List,Oddlist,Evenlist).
odd([H|T],Oddlist,Evenlist):-even(T,[H|Oddlist],Evenlist).
odd([],_,_).
even([H|T],Oddlist,Evenlist):-odd(T,Oddlist,[H|Evenlist]).
even([],_,_).
但我得到的唯一 return 类似 Oddlist = _7132946 Evenlist = _26997888.
我不知道我做错了什么。我会很感激任何帮助。谢谢!
你的想法必须提炼...
首先,每种语言(不仅是 Prolog)都需要符号命名一致。所以我根据需要重命名了变量。
特定于 Prolog,有一种特定的方法来 'cons' 列表,源自应用于规则头的模式匹配。这同样适用于基本情况:我们必须提供将绑定调用方变量的空列表。
全部代码:
split(List,Odd,Even):-odd(List,Odd,Even).
odd([H|T],[H|Odd],Even):-even(T,Odd,Even).
odd([],[],[]).
even([H|T],Odd,[H|Even]):-odd(T,Odd,Even).
even([],[],[]).
CapelliC 的回答很完美。简单说明一下:
当你有这样的 Prolog 子句时:
foo([H|T], [H|Z]) :-
foo(T, Z).
然后你可以这样称呼它:
?- foo([a,b,c], L).
from: foo([H| T ], [H|Z]) with H = a, T = [b,c], L = [a|Z]
call: foo([a|[b,c]], [a|Z])
然后导致递归调用:
call: foo([b,c], Z).
from: foo([H| T ], [H|Z]) with H = b, T = [c], L = [b|Z]
call: foo([b|[c]], [b|Z])
此时,你一开始做的列表,[a|Z]
现在是[a|[b|Z]]
,也就是[a,b|Z]
.
因此,您在作为第二个参数传递的变量中创建一个列表,并将 H 放在列表的前面。您提供给递归调用的列表的其余部分。您将不断向列表末尾添加元素,直到第一个列表为空列表。届时,您也将结束新列表:
foo([], []).
在您的示例中,还有另一个谓词与第一个谓词相互递归:
foo([], [], []).
foo([H|T], [H|F], B) :-
bar(T, F, B).
bar([], [], []).
bar([H|T], F, [H|B]) :-
foo(T, F, B).
当然,这会"unzip"一个列表变成两个列表。
我知道这个 post 现在已经很旧了,但我想我也会添加我的解决方案,所以如果有人像我 15 分钟前一样,他们还有其他东西要看。这种方式以创建最终列表的方式向后构建列表。前 3 行是基本情况。
split_odd_even([], [], []).
split_odd_even([O], [O], []).
split_odd_even([O,E], [O], [E]).
split_odd_even([O,E|T], [O|OL], [E|EL]) :- split_odd_even(T, OL, EL).
我正在尝试将一个列表拆分为另外两个列表。列出偶数,元素处于偶数位置,列表奇数与其他元素。我一直在网上寻找解决方案,但在我看来都像中文,我无法理解这个过程。所以这就是我一直在尝试的:
split(List,Odd,Even):-odd(List,Oddlist,Evenlist).
odd([H|T],Oddlist,Evenlist):-even(T,[H|Oddlist],Evenlist).
odd([],_,_).
even([H|T],Oddlist,Evenlist):-odd(T,Oddlist,[H|Evenlist]).
even([],_,_).
但我得到的唯一 return 类似 Oddlist = _7132946 Evenlist = _26997888.
我不知道我做错了什么。我会很感激任何帮助。谢谢!
你的想法必须提炼...
首先,每种语言(不仅是 Prolog)都需要符号命名一致。所以我根据需要重命名了变量。
特定于 Prolog,有一种特定的方法来 'cons' 列表,源自应用于规则头的模式匹配。这同样适用于基本情况:我们必须提供将绑定调用方变量的空列表。
全部代码:
split(List,Odd,Even):-odd(List,Odd,Even).
odd([H|T],[H|Odd],Even):-even(T,Odd,Even).
odd([],[],[]).
even([H|T],Odd,[H|Even]):-odd(T,Odd,Even).
even([],[],[]).
CapelliC 的回答很完美。简单说明一下:
当你有这样的 Prolog 子句时:
foo([H|T], [H|Z]) :- foo(T, Z).
然后你可以这样称呼它:
?- foo([a,b,c], L). from: foo([H| T ], [H|Z]) with H = a, T = [b,c], L = [a|Z] call: foo([a|[b,c]], [a|Z])
然后导致递归调用:
call: foo([b,c], Z). from: foo([H| T ], [H|Z]) with H = b, T = [c], L = [b|Z] call: foo([b|[c]], [b|Z])
此时,你一开始做的列表,[a|Z]
现在是[a|[b|Z]]
,也就是[a,b|Z]
.
因此,您在作为第二个参数传递的变量中创建一个列表,并将 H 放在列表的前面。您提供给递归调用的列表的其余部分。您将不断向列表末尾添加元素,直到第一个列表为空列表。届时,您也将结束新列表:
foo([], []).
在您的示例中,还有另一个谓词与第一个谓词相互递归:
foo([], [], []). foo([H|T], [H|F], B) :- bar(T, F, B). bar([], [], []). bar([H|T], F, [H|B]) :- foo(T, F, B).
当然,这会"unzip"一个列表变成两个列表。
我知道这个 post 现在已经很旧了,但我想我也会添加我的解决方案,所以如果有人像我 15 分钟前一样,他们还有其他东西要看。这种方式以创建最终列表的方式向后构建列表。前 3 行是基本情况。
split_odd_even([], [], []).
split_odd_even([O], [O], []).
split_odd_even([O,E], [O], [E]).
split_odd_even([O,E|T], [O|OL], [E|EL]) :- split_odd_even(T, OL, EL).