Как вывести массив с вложенными массивами в Pascal - PullRequest
0 голосов
/ 02 мая 2018

Я создаю базовую концепцию музыкального проигрывателя с использованием Pascal, но я изо всех сил пытаюсь показать альбомы внутри него. Полученная ошибка говорит: «(134, 29) Ошибка: невозможно прочитать или записать переменные этого типа». Я предполагаю, что это говорит, потому что я использую массив в массиве, и ему трудно отображать оба одновременно (хотя я хочу, чтобы он отображал только альбомы, а не дорожки).

Вот как выглядит мой код:

function ReadAllTrack(prompt: String): Tracks;
var
    i: Integer;
    trackArray: Array of Track;
    trackCount: Integer;
begin
    WriteLn(prompt);
    trackCount := ReadIntegerGreaterThan1('Please enter the number of tracks you would like to add: ');
    Setlength(trackArray, trackCount);
    for i := 0 to trackCount - 1 do
    begin
        WriteLn('Enter the details for your track:');    
        trackArray[i] := ReadTrack();
    end;
    result := trackArray;
end;

function ReadAlbum(): Album;
begin
    result.albumName := ReadString('Album name: ');
    result.artistName := ReadString('Artist name: ');
    result.albumGenre := ReadGenre('Genre:');
    result.trackCollection := ReadAllTrack('Track Collection:');
end;

function ReadAllAlbums(): Albums;
var
    i: Integer;
    albumArray: Array of Album;
    albumCount: Integer;
begin
    albumCount := ReadIntegerGreaterThan1('Please enter the number of albums you would like to add: ');
    Setlength(albumArray, albumCount);
    for i := 0 to albumCount - 1 do
    begin
        WriteLn('Enter the details for your album:');
        albumArray[i] := ReadAlbum();
    end;
    result := albumArray;
end;

procedure DisplayAlbumOptions(listOfAllAlbums: Albums);
var
    userInput: Integer;
begin
    WriteLn('1. Display all albums');
    WriteLn('2. Display all albums for a genre');
    userInput := ReadIntegerRange('Please enter a number (1, 2) to select: ', 1, 2);

    case userInput of
        1: WriteLn(listOfAllAlbums); //Error: Can't read or write variables of this type
    end;
end;

По сути, он запрашивает у пользователя 5 вариантов: 1. Добавить альбомы 2. Показать альбомы и т.д.

Если пользователь выбирает 1, программа попросит пользователя ввести количество альбомов, которые он хочет ввести. Затем для каждого альбома будет предложено ввести данные, а затем треки.

Затем, если пользователь выбирает 2, программа попросит пользователя выбрать либо отображение каждого отдельного альбома, либо отображение всех альбомов для одного жанра (я буду работать над этим после решения этой проблемы). Сначала я думал, что это будет так же просто, как WriteLn(TheAlbumArray);, но оказалось, что это было сложнее, чем я думал, потому что я не думаю, что для программы возможно отобразить это таким образом. Я попытался разделить альбомы и дорожки так, чтобы они отображались только при использовании WriteLn(TheAlbumArray);, но это было невозможно, потому что дорожки все еще должны быть «внутри» альбома, чтобы при отображении альбомов и выборе одного из их, то будет отображать треки ....

Любая помощь или предложение по этому и / или второму будет высоко ценится ^^

Ответы [ 2 ]

0 голосов
/ 02 мая 2018

Невозможно использовать составные типы (массивы, записи, ...) в Read[ln] и Write[ln] процедурах.

Чтобы сделать ваш код более прозрачным, вы можете создать помощник типов для ваших массивов и использовать известное свойство AsString. Вот пример для простого array of Integer:

program foo;

{$mode objfpc}{$H+}
{$modeswitch typehelpers}

uses
    Classes, SysUtils;

type
    TMyArray = array of Integer;

    TMyArrayHelper = type helper for TMyArray
    private
        function GetAsString: string;
        procedure SetAsString(const AValue: string);
    public
        property AsString: string read GetAsString write SetAsString;
    end;

function TMyArrayHelper.GetAsString: string;
var
    i: Integer;
begin
    Result := '';
    for i in Self do
    begin
        if Result <> '' then
            Result := Result + ', ';
        Result := Result + IntToStr(i);
    end;
    Result := '[' + Result + ']';
end;

// Relatively simple parser
// Fill free to implement ones for your array type
procedure TMyArrayHelper.SetAsString(const AValue: string);
var
    tmp, s: string;
    items: TStringArray;
    i: Integer;
begin
    tmp := Trim(AValue);
    if not (tmp.StartsWith('[') and tmp.EndsWith(']')) then
        raise Exception.CreateFmt('Invalid array literal format: "%s"', [tmp]);
    tmp := tmp.Trim(['[', ']']);
    items := tmp.Split([',']);
    for s in items do
        try
            StrToInt(s);
        except
            on e: Exception do
                raise Exception.CreateFmt('Invalid integer literal: "%s"', [s]);
        end;
    SetLength(Self, Length(items));
    for i := 0 to Length(items) - 1 do
        Self[i] := StrToInt(items[i]);
end;

var
    a1, a2: TMyArray;
begin
    a1.AsString := '[1,2,3,5]';
    Writeln('a1 = ', a1.AsString);
    a2.AsString := a1.AsString;
    a2[1] := 999;
    Writeln('a2 = ', a2.AsString);
end.
0 голосов
/ 02 мая 2018

Ваш оригинальный вопрос содержал много лишних деталей. После редактирования вы удалили объявления типов, но сохранили большую часть лишних деталей.

Тем не менее, можно определить проблему, когда вы передаете массив записей в Writeln. Функция Writeln может принимать только определенные простые типы в качестве аргументов, например, строки, числовые типы, логические. Вы, конечно, не можете передать массив в Writeln. Вы должны перебрать массив и обработать каждый элемент в отдельности.

Так что вы можете попробовать

for i := low(listOfAllAlbums) to high(listOfAllAlbums) do
  WriteLn(listOfAllAlbums[i]);

Но это тоже не работает, потому что listOfAllAlbums[i] - это запись, а запись - составной тип, который нельзя передать в Writeln. Поэтому вам нужно обрабатывать запись отдельно. Если вы хотите отобразить только заголовок, вы пишете:

for i := low(listOfAllAlbums) to high(listOfAllAlbums) do
  WriteLn(listOfAllAlbums[i].albumName);

Если вы тоже хотите напечатать названия треков, вам нужно перебрать массив, содержащийся в записи.

for i := low(listOfAllAlbums) to high(listOfAllAlbums) do
begin
  WriteLn(listOfAllAlbums[i].albumName);
  for j := low(trackCollection) to high(trackCollection) do
    WriteLn(listOfAllAlbums[i].trackCollection[j]);
end;
...