Let’s say that I guessed that I need ten elements for my array.
But while generating values for that array, I only used, say, nine of them.
When compiling would I get a warning about undefined value(s)?
In Perl (!!) I could ask if an array index is undefined and use that to carefully only use the part of the array I needed.
Here’s my dilemma:
I want to generate a list of all factors of a positive integer and preserve it in an array.
I’m still trying to find a method of determining the correct size of the array, but haven’t found it yet.
So, if my array is too small, I fail to generate (and preserve) all of the factors.
If my array is too big, then I easily could run into a run-time error (or worse!) by accessing undefined data.
One way to do this is for me to place negative integers in the part of the array that I don’t use, but that defeats the purpose of defining the array only to have positive integers.
Perhaps I should create an array of Natural numbers and define all elements to the value 0. Then the parts I use will have Positive values and I can ignore any elements containing zeros. Then, apart from determining an exact way to declare the array of the proper size, I will be safe.
You could use a vector to hold them. It grows dynamically as you add more elements. It is indexible just like an array. Take a look at the package Ada.Containers.Vectors
with Ada.Text_IO; use Ada.Text_IO;
with Ada.Containers.Vectors;
procedure jdoodle is
package Positive_Vectors is new Ada.Containers.Vectors
(Index_Type => Positive,
Element_Type => Positive);
Factors : Positive_Vectors.Vector;
begin
Put_Line("Number of Elements:" & Factors.Length'Image);
Put_Line("Adding elements ...");
Factors.Append(2);
Factors.Append(3);
Put_Line("Number of Elements:" & Factors.Length'Image);
Put_Line("Indexing the vector like an array ...");
Put_Line("Factors(1) =" & Positive'Image(Factors(1)));
Put_Line("Factors(2) =" & Positive'Image(Factors(2)));
Put_Line("Iterating over the vector like an array ...");
for Factor of Factors loop
Put_Line("Factor of" & Factor'Image);
end loop;
end jdoodle;
Output:
Number of Elements: 0
Adding elements ...
Number of Elements: 2
Indexing the vector like an array ...
Factors(1) = 2
Factors(2) = 3
Iterating over the vector like an array ...
Factor of 2
Factor of 3
gcc -c jdoodle.adb
gnatbind -x jdoodle.ali
gnatlink jdoodle.ali -o jdoodle
Thank you very much. This is much better than trying to guess how large the array should be, guessing too small is bad, guessing too big is bad, and there doesn’t seem to be a good way to know for sure in advance exactly how large it should be, and using “sentinel values” (a default assignment of zero) to an array that is bigger than needed is not good either.
Appreciate not only the clue to use the Ada.Containers.Vectors to replace the array but also some example code on how to use it.
In addition to using vectors, you could use a recursive function to build up your list. Something like
type Factor_List is array (Positive range <>) of Positive;
...
function List_For (Number : in Positive) return Factor_List is
function List_For (Number : in Positive; From : in Positive) return Factor_List is
Factor : Positive;
Exists : Boolean;
begin
Find_Next_Factor (Number => Number, From => From, Factor => Factor, Exists => Exists);
if Exists then
return Factor & List_For (Number, Factor);
end if;
return (1 .. 0 => 1);
end List_For;
begin
return List_For (Number, 1);
end List_For;
Hm, I would suggest that the problem is you’re not using unconstrained arrays.
Type Sequence is Array(Positive range <>) of Natural;
Null_Sequence : Constant Sequence := (2..1 => <>);
Type Factorization(Negative : Boolean; Length : Natural) is record
Factors : Sequence( 1..Length ) := (others => 0);
end record;
Function Factors(Value : Natural) return Factorization is
Function Factorize( X : Natural := abs Value;
Working : Sequence := Null_Sequennce
) return Sequence is
Begin
case Value is
when 0 | 1 => return Working;
when 2 => return Sequence'( 1 => 1 );
when 3 => return Sequence'( 1 => 0, 2 => 1 );
when others =>
if Working'Length not in 1..Sqrt(Value)-1 then
Return Working;
else
Declare
This : Positive renames Xth_Prime( X );
Remain : Constant Natural := X mod This;
Divides : Constant Boolean := Remain = 0;
Value : Constant Natural := (if Divides then X div This else X);
Begin
Return Factorize(Value, Working & Remain);
End;
end if;
end case;
End Factorize;
Temp : Sequence renames Factorize;
Begin
Return Result : Constant Factorization:=
(Length => Temp'Length,
Negative => Value not in Natural,
Factors => Temp
);
End Factors;
Um, I think…
I just typed it out; not compiled or anything.
(More a “how to use unconstrained arrays and variant-records” example.)