Прочитать файл и сохранить в список - PullRequest
0 голосов
/ 06 июля 2018

У меня есть файл вида:

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), Я думаю. Это мой первый контакт с прологом, поэтому я не уверен, что происходит. Как я могу исправить код выше?

1 Ответ

0 голосов
/ 06 июля 2018

Я бы определенно подошел к этому с s. Идея состоит в том, чтобы создать простую грамматику для ввода и использовать ее для анализа файла.

:- 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. Они анализируют пробел, включая переводы строк, несколько пробелов, включая переводы строк, и несколько символов пробелов , а не , включая переводы строк и целые числа.

Грамматика гласит, что вход состоит из целого числа N, пустой строки и нескольких команд. Команды или команда, бланк, и еще несколько команд, или мы закончили. Та же идея развернута, чтобы получить команду: у нас либо есть целое число и несколько пробелов и еще несколько целых чисел, или мы закончили. Обратите внимание, насколько короче и более декларативна версия 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]] .

Наслаждайтесь!

Edit : Я бы, вероятно, не изменил это, чтобы вернуть 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 (=..), чтобы создать термин из списка. Опять же, я бы не стал использовать эту идею здесь, потому что ваша обработка станет более сложной, вероятно, без реальной выгоды.

...