commandlinegamer
commandlinegamer

Reputation: 111

Looping through Ada arrays using strings

I have loaded some data from a file into three arrays of type Unbounded_String, which I'll call Days, Months, and Seasons.

Each of these arrays has a corresponding Integer which has recorded the number of items in the array, viz. Days_Total, Months_Total, and Seasons_Total.

I'd like to iterate through the three arrays, and output all the data, ideally something of the form (and this is pseudo-Ada):

for Count_1 in (Days, Months, Years) loop
  for Count_2 in 1 .. (Count_1)_Total loop
      Put_Line (Count_1 (Count_2));
  end loop;
end loop;

Whereas what I'm actually doing at the moment is

for Count in 1 .. Days_Total loop
   Put_Line (Days (Count));
end loop;

for Count in 1 .. Months_Total loop
   Put_Line (Months (Count));
end loop;

for Count in 1 .. Seasons_Total loop
   Put_Line (Seasons (Count));
end loop;

I'm guessing I need to use an Access Type, but at the moment am having trouble getting my round it. The full example program is (load_data_example.adb):

with Ada.Strings.Unbounded, Text_IO, Ustrings;
use  Ada.Strings.Unbounded, Text_IO, Ustrings;




procedure Load_Data_Example is



   Max_Items                   : Constant := 12;
   Datafile                    : File_Type;
   Datafile_Name               : String := "datafile";

   type Small_String_Array is array (1 .. Max_Items)
     of Unbounded_String;

   Days, Months, Seasons       : Small_String_Array;
   Days_Total, Months_Total    : Integer := 0;
   Seasons_Total               : Integer := 0;
   Datafile_Len, Datafile_Skip : Integer := 0;
   Line_Count, Lines_Expected  : Integer := 0;
   Data_Index, Input_Len       : Integer := 0;
   Input                       : Unbounded_String;



begin


    Open (Datafile, In_File, Datafile_Name);

    while (not End_Of_File (Datafile)) loop

       Get_Line (Datafile, Input);
       Datafile_Len := Datafile_Len + 1;
       Input_Len := Length (Input);

       if Line_Count <= (Lines_Expected - 1) then

          Line_Count := Line_Count + 1;

       end if;

       if Datafile_Len = (Datafile_Skip + 1) then

          Line_Count := 0;
          Data_Index := Data_Index + 1;
          Lines_Expected := Integer'Value (To_String (Input));
          Datafile_Skip := Datafile_Skip + Lines_Expected + 1;

       else

          case Data_Index is

             when      1  =>  Days (Line_Count) := Input;
                              Days_Total := Days_Total + 1;

             when      2  =>  Months (Line_Count) := Input;
                              Months_Total := Months_Total + 1;

             when      3  =>  Seasons (Line_Count) := Input;
                              Seasons_Total := Seasons_Total + 1;

             when others  =>  null;

          end case;

       end if;

    end loop;

    Close (Datafile);


    for Count in 1 .. Days_Total loop
       Put_Line (Days (Count));
    end loop;

    for Count in 1 .. Months_Total loop
       Put_Line (Months (Count));
    end loop;

    for Count in 1 .. Seasons_Total loop
       Put_Line (Seasons (Count));
    end loop;


end Load_Data_Example;

And the datafile is:

3
Monday
Tuesday
Friday
4
April
June
August
September
2
Spring
Winter

Any hints would be really appreciated.

Upvotes: 1

Views: 1127

Answers (2)

flyx
flyx

Reputation: 39638

Expanding on Brian's answer: In Ada 2012, you have containers that implement bounded vectors like those you use. Instead of taking care of incrementing and checking the total yourself, you can use those:

   package String_Vectors is new Ada.Containers.Bounded_Vectors
     (Positive, Unbounded_String);
   type Categories is (Days, Months, Seasons);
   Items : array (Categories) of String_Vectors.Vector (12);

begin
   --  ... other code here

   for Catogory in Categories loop
      for Item of Items (Category) loop
         --  using Ada 2012 iterators in this for loop.
         --  only yields the items that have actually been appended
         --  to the vector.

         Put_Line (Item);
      end loop;
   end loop;

Upvotes: 3

user1818839
user1818839

Reputation:

One approach: collect everything about each case in a record, and build an array of those records you can sequence over.

type Item_List is record
   Total : natural;
   Names : Small_String_Array;
end record;

type Categories is (Days, Months, Seasons);

Items : array (Categories) of Item_List;

for Count_1 in Categories loop
  for Count_2 in 1 .. Items(Count_1).Total loop
      Put_Line (Items(Count_1).Names(Count_2));
  end loop;
end loop;

Upvotes: 4

Related Questions