迭代列表同时追加到另一个列表

问题描述 投票:0回答:1

我是 Prolog 新手。以下谓词应该处理一个字符串列表,每个字符串包含以空格分隔的名字和姓氏。它的目的是遍历每个元素,用空格将其分隔为一个用于 FirstName 的元素和另一个用于 LastName 的元素,并将这些值添加到 FirstNames 列表和 LastNames 列表中。最后,它应该返回所有名字和姓氏的列表,两者都与原始列表的顺序相对应。我正在努力让它发挥作用。

populate([]).
populate([H|T], FirstNames, LastNames) :-
    split_string(H, " ", " ", Elems),
    Elems = [FirstName, LastName],
    append(FirstNames, [FirstName], FirstNames2),
    append(LastNames, [LastName], LastNames2),
    populate(T, FirstNames, LastNames).

例如,如果给定

?- populate(["Peter Parker", "Bruce Wayne"], FirstNames, LastNames), 

应该会回来

FirstNames = ["Peter", "Bruce"]

LastNames = ["Parker", "Wayne"].
prolog
1个回答
1
投票

在 SWI-Prolog 中对问题进行编码,具有以下特点:

  • 使用定语从句语法将 Name 分成 First NameLast Name
  • 利用库
    dcg/basics
    ,更准确地使用规则
    nonblanks//1
    blank//0
    分别处理非空白和单字符空白
  • SWI-Prolog DCG 处理文本假定 unicode 代码列表作为输入(而不是字符列表),因此我们通过使用
    atom_codes/2
    来拆分和重组文本来尊重这一点 -
  • 为了一致性,在整个过程中使用原子 (
    'John Wayne'
    ) 而不是 SWI-Prolog 字符串 (
    "John Wayne"
    )。
  • 使用 plunit 单元测试进行说明。

所以:

首先使用 DCG 编写一个小谓词,将“名称原子”分解为“名字原子”和“姓氏原子”:

:- use_module(library(dcg/basics)).

name(First,Last) --> 
   nonblanks(FirstCodes),   % collect a list of codes for the first name 
   blank,                   % then comes a blank
   nonblanks(LastCodes),    % collect a list of codes for the last name
   { atom_codes(First,FirstCodes),   % fuse the codes into a "first name atom"
     atom_codes(Last,LastCodes) }.   % fuse the codes into a "last name atom"
     
separate(Name,First,Last) :-
   atom_codes(Name,NameCodes),
   phrase(name(First,Last),NameCodes).

separate/3
我们可以测试一下:

:- begin_tests(separate).

test(1) :-
   separate('Bruce Wayne',First,Last),
   assertion(First == 'Bruce'),
   assertion(Last == 'Wayne').

:- end_tests(separate).

运行测试用例看起来不错:

?- run_tests(separate).
% PL-Unit: separate . done
% test passed
true.

现在我们只需要将

separate/3
应用于姓名列表即可。我们可以使用
maplist/3
但我们只使用递归定义:

% separate_all(+ListOfNames,-ListOfFirsts,.ListOfLasts)

separate_all([],[],[]).
separate_all([Name|Ns],[First|Fs],[Last|Ls]) :-
   separate(Name,First,Last),
   separate_all(Ns,Fs,Ls).

还有一个测试用例:

:- begin_tests(separate_all).

test(all_1) :-
   separate_all(['Peter Parker', 'Bruce Wayne'],FirstNames,LastNames),
   assertion(FirstNames == ['Peter','Bruce']),
   assertion(LastNames == ['Parker','Wayne']).

:- end_tests(separate_all).

所以:

?- run_tests(separate_all).
% PL-Unit: separate_all . done
% test passed
true.
© www.soinside.com 2019 - 2024. All rights reserved.