读取文件并保存到列表
Read a file and save to a list
我有一个格式的文件:
3
1 2 3 4 5
4 5 6
1 6 2 4 6 7
第一行标识接下来的几行。这些行反过来只是一系列数字。我需要将其保存到可能如下所示的列表中:
N = 3,
Teams = [line(1, 2, 3, 4, 5), line(4, 5, 6), line(1, 6, 2, 4, 6, 7)].
到目前为止我正在尝试的是:
read_file(File, N, Lines) :-
open(File, read, Stream),
read_line_to_codes(Stream, Line),
atom_codes(Atom, Line),
atom_number(Atom, N),
read_lines(Stream, N, Lines).
read_lines(Stream, N, Lines) :-
( N == 0 -> Lines = []
; N > 0 -> read_line(Stream, N, Line),
Nm1 is N-1,
read_lines(Stream, Nm1, RestLines),
Lines = [Line | RestLines]).
read_line(Stream, N, line()) :-
read_line_to_codes(Stream, Line),
atom_codes(Atom, Line),
atomic_list_concat([N | Atoms], ' ', Atom),
maplist(atom_number, Atoms, []).
但我认为 atomic_list_concat([N | Atoms], ' ', Atom),
似乎有问题。这是我第一次接触序言,所以我不确定发生了什么。我该如何修复上面的代码?
我肯定会用 dcg 来解决这个问题。这里的想法是为您的输入创建一个简单的语法并使用它来解析文件。
:- use_module(library(dcg/basics)).
input(N, Teams) --> integer(N), blanks, teams(Teams).
teams([Team|Teams]) --> team(Team), blank, teams(Teams).
teams([]) --> [].
team([X|Xs]) --> integer(X), whites, team(Xs).
team([]) --> [].
库 dcg/basics
为我们提供了我们在这里使用的四个实用函数:blank
、blanks
、whites
和 integer/1
。这些解析包含换行符的空白 space、包含换行符的多个空白 space 和包含换行符的多个白色 space 字符 not 和整数。
语法说一个输入包含一个整数N,一个空行,然后是一些队。这些团队要么是一个团队,一个空白的团队,要么是更多的团队,否则我们就完成了。部署相同的想法来获得一个团队:我们要么有一个整数和一些 spaces 和一些更多的整数,要么我们就完成了。请注意 DCG 版本比字节处理方法更短、更具声明性!
使用起来也相当简单:
?- phrase_from_file(input(N, Teams), 'input.txt').
N = 3,
Teams = [[1, 2, 3, 4, 5], [4, 5, 6], [1, 6, 2, 4, 6, 7]] ;
false.
如果需要,您可以将其提升到实用谓词中:
parse(Filename, N, Teams) :- phrase_from_file(input(N, Teams), Filename).
?- parse('input.txt', N, Teams).
N = 3,
Teams = [[1, 2, 3, 4, 5], [4, 5, 6], [1, 6, 2, 4, 6, 7]] .
尽情享受吧!
编辑:我可能不会将其更改为return line(1,2,3,4,5), line(4,5,6), ...
,因为您会发现处理可变元数结构很不愉快。但是如果你真的想要,你可以用这个代替 team//1
规则:
team(Team) --> team_list(TeamList), { Team =.. [list|TeamList] }.
team_list([X|Xs]) --> integer(X), whites, team_list(Xs).
team_list([]) --> [].
这里我们使用 univ (=..
) 从列表中构建一个术语。同样,我不会在这里部署这个想法,因为您的处理将变得更加复杂而可能没有真正的收益。
我有一个格式的文件:
3
1 2 3 4 5
4 5 6
1 6 2 4 6 7
第一行标识接下来的几行。这些行反过来只是一系列数字。我需要将其保存到可能如下所示的列表中:
N = 3,
Teams = [line(1, 2, 3, 4, 5), line(4, 5, 6), line(1, 6, 2, 4, 6, 7)].
到目前为止我正在尝试的是:
read_file(File, N, Lines) :-
open(File, read, Stream),
read_line_to_codes(Stream, Line),
atom_codes(Atom, Line),
atom_number(Atom, N),
read_lines(Stream, N, Lines).
read_lines(Stream, N, Lines) :-
( N == 0 -> Lines = []
; N > 0 -> read_line(Stream, N, Line),
Nm1 is N-1,
read_lines(Stream, Nm1, RestLines),
Lines = [Line | RestLines]).
read_line(Stream, N, line()) :-
read_line_to_codes(Stream, Line),
atom_codes(Atom, Line),
atomic_list_concat([N | Atoms], ' ', Atom),
maplist(atom_number, Atoms, []).
但我认为 atomic_list_concat([N | Atoms], ' ', Atom),
似乎有问题。这是我第一次接触序言,所以我不确定发生了什么。我该如何修复上面的代码?
我肯定会用 dcg 来解决这个问题。这里的想法是为您的输入创建一个简单的语法并使用它来解析文件。
:- use_module(library(dcg/basics)).
input(N, Teams) --> integer(N), blanks, teams(Teams).
teams([Team|Teams]) --> team(Team), blank, teams(Teams).
teams([]) --> [].
team([X|Xs]) --> integer(X), whites, team(Xs).
team([]) --> [].
库 dcg/basics
为我们提供了我们在这里使用的四个实用函数:blank
、blanks
、whites
和 integer/1
。这些解析包含换行符的空白 space、包含换行符的多个空白 space 和包含换行符的多个白色 space 字符 not 和整数。
语法说一个输入包含一个整数N,一个空行,然后是一些队。这些团队要么是一个团队,一个空白的团队,要么是更多的团队,否则我们就完成了。部署相同的想法来获得一个团队:我们要么有一个整数和一些 spaces 和一些更多的整数,要么我们就完成了。请注意 DCG 版本比字节处理方法更短、更具声明性!
使用起来也相当简单:
?- phrase_from_file(input(N, Teams), 'input.txt').
N = 3,
Teams = [[1, 2, 3, 4, 5], [4, 5, 6], [1, 6, 2, 4, 6, 7]] ;
false.
如果需要,您可以将其提升到实用谓词中:
parse(Filename, N, Teams) :- phrase_from_file(input(N, Teams), Filename).
?- parse('input.txt', N, Teams).
N = 3,
Teams = [[1, 2, 3, 4, 5], [4, 5, 6], [1, 6, 2, 4, 6, 7]] .
尽情享受吧!
编辑:我可能不会将其更改为return line(1,2,3,4,5), line(4,5,6), ...
,因为您会发现处理可变元数结构很不愉快。但是如果你真的想要,你可以用这个代替 team//1
规则:
team(Team) --> team_list(TeamList), { Team =.. [list|TeamList] }.
team_list([X|Xs]) --> integer(X), whites, team_list(Xs).
team_list([]) --> [].
这里我们使用 univ (=..
) 从列表中构建一个术语。同样,我不会在这里部署这个想法,因为您的处理将变得更加复杂而可能没有真正的收益。