根据列表中的分隔符拆分序言列表?
Splitting a prolog list based on a delimiter from the list?
在 Prolog 中,假设我有一个列表,例如
[fun, joke1, joke2, fun, joke3, fun, joke4, joke5, joke6]
我正在尝试构建一个列表列表,结果是
[ [joke1, joke2], [joke4, joke5, joke6] ]
使用 fun 作为分隔符并忽略长度为 1 的内置列表,因此
[joke3]
不在该列表中。
我尝试使用 split_string 但它对我需要获得的东西不起作用。我也尝试过使用 append 进行递归,但效果不佳。希望能给我指明正确的方向。
谢谢!
这是一个使用两个谓词的解决方案:
split_on_delimiter(L, D, S) :-
split_on_delimiter_(L, D, R),
findall(X, (member(X, R), length(X,Length), Length > 1), S).
split_on_delimiter_([], _, [[]]).
split_on_delimiter_([D|T], D, [[]|T2]) :-
split_on_delimiter_(T, D, T2).
split_on_delimiter_([H|T], D, [[H|T2]|T3]) :-
dif(H, D),
split_on_delimiter_(T, D, [T2|T3]).
split_on_delimiter_/3
是根据分隔符 D
真正拆分列表的谓词。 split_on_delimiter/3
是您要调用的谓词,它将依次调用 split_on_delimiter_/3
.
为了仅保留长度大于 1 的子列表,我们使用 findall
查找拆分结果的所有子列表 Length > 1
.
split_on_delimiter_/3
本身相当简单:
- 第一条规则:拆分一个空列表只会产生一个子列表:空列表。
- 第二条规则:当列表的第一个元素是分隔符时,结果是空列表,后面是递归调用的结果。
- 第三条规则:当列表的第一个元素不是分隔符(
dif(H, D)
)时,我们将该元素放在第一个子列表的开头并递归调用。
一个例子:
?- split_on_delimiter([fun, joke1, joke2, fun, joke3, fun, joke4, joke5, joke6], fun, Z).
Z = [[joke1, joke2], [joke4, joke5, joke6]] ;
false.
备注
split_on_delimiter_/3
有多余的选择点(这就是为什么你可以在第一个结果后按;
,因为它认为可以有更多的答案但是有none)。您可以使用 !
或 once
.
解决此问题
删除这些选择点的更好解决方案是使用 if_/3
和 (=)/3
或 module(reif)
(尽管我怀疑这对您有用):
split_on_delimiter_(L, D, [L2|T2]) :-
if_(L = [],
[L2|T2] = [[]],
( L = [H|T],
if_(H = D,
( L2 = [],
split_on_delimiter_(T, D, T2)
),
( L2 = [H|T3],
split_on_delimiter_(T, D, [T3|T2])
)
)
)
).
在 Prolog 中,假设我有一个列表,例如
[fun, joke1, joke2, fun, joke3, fun, joke4, joke5, joke6]
我正在尝试构建一个列表列表,结果是
[ [joke1, joke2], [joke4, joke5, joke6] ]
使用 fun 作为分隔符并忽略长度为 1 的内置列表,因此
[joke3]
不在该列表中。
我尝试使用 split_string 但它对我需要获得的东西不起作用。我也尝试过使用 append 进行递归,但效果不佳。希望能给我指明正确的方向。
谢谢!
这是一个使用两个谓词的解决方案:
split_on_delimiter(L, D, S) :-
split_on_delimiter_(L, D, R),
findall(X, (member(X, R), length(X,Length), Length > 1), S).
split_on_delimiter_([], _, [[]]).
split_on_delimiter_([D|T], D, [[]|T2]) :-
split_on_delimiter_(T, D, T2).
split_on_delimiter_([H|T], D, [[H|T2]|T3]) :-
dif(H, D),
split_on_delimiter_(T, D, [T2|T3]).
split_on_delimiter_/3
是根据分隔符 D
真正拆分列表的谓词。 split_on_delimiter/3
是您要调用的谓词,它将依次调用 split_on_delimiter_/3
.
为了仅保留长度大于 1 的子列表,我们使用 findall
查找拆分结果的所有子列表 Length > 1
.
split_on_delimiter_/3
本身相当简单:
- 第一条规则:拆分一个空列表只会产生一个子列表:空列表。
- 第二条规则:当列表的第一个元素是分隔符时,结果是空列表,后面是递归调用的结果。
- 第三条规则:当列表的第一个元素不是分隔符(
dif(H, D)
)时,我们将该元素放在第一个子列表的开头并递归调用。
一个例子:
?- split_on_delimiter([fun, joke1, joke2, fun, joke3, fun, joke4, joke5, joke6], fun, Z).
Z = [[joke1, joke2], [joke4, joke5, joke6]] ;
false.
备注
split_on_delimiter_/3
有多余的选择点(这就是为什么你可以在第一个结果后按;
,因为它认为可以有更多的答案但是有none)。您可以使用 !
或 once
.
删除这些选择点的更好解决方案是使用 if_/3
和 (=)/3
或 module(reif)
(尽管我怀疑这对您有用):
split_on_delimiter_(L, D, [L2|T2]) :-
if_(L = [],
[L2|T2] = [[]],
( L = [H|T],
if_(H = D,
( L2 = [],
split_on_delimiter_(T, D, T2)
),
( L2 = [H|T3],
split_on_delimiter_(T, D, [T3|T2])
)
)
)
).