Operating on internal tables with header line - append

I have a question about internal tables' header line.
I assigned some values into in_table1 and then try to add a record with APPEND command into in_table2 in the following block of code.
But I cannot see the record that I have appended into in_table2.
Is this because of the header line of in_table2?
If yes, how can I see the records anyway?
*&---------------------------------------------------------------------*
*& Report ZTEST_LOOP
*&
*&---------------------------------------------------------------------*
*&
*&
*&---------------------------------------------------------------------*
REPORT ZTEST_STRUCT_DATA_TYPE.
***** define structure data types
TYPES: BEGIN OF adres_bilgileri, " this is a struct with a set of types
sokak type c length 30,
cadde type c length 30,
sehir type c length 15,
ev_no type n length 4,
end of adres_bilgileri.
types: BEGIN OF personel_bilgileri,
ad type c LENGTH 20,
soyad type c LENGTH 20,
tel_no type n LENGTH 12,
adres TYPE adres_bilgileri," ********************!!!!!!!!!!!!!!!!!!!!!!
END OF personel_bilgileri.
TYPES personel_bilgi_tablosu TYPE STANDARD TABLE OF personel_bilgileri WITH key TABLE_LINE.
data: in_table1 type personel_bilgileri,
in_table2 type personel_bilgi_tablosu WITH HEADER LINE.
"adres1 type adres_bilgileri.
in_table1-ad = 'Latife'.
in_table1-soyad = 'A'.
in_table1-adres-sokak = 'Hasanpaşa'. """"""""""""adresten sokak bilgisine geçiş
in_table1-adres-ev_no = 10.
append in_table1 to in_table2.
WRITE / : 'Records in in_table2:', in_table2.

First of all, you should not use internal tables with header anymore.
Second of all, if you really have to do it, here is some solution.
The header in_table2 is of course empty in your case. You have to loop through the table to print it out. For example like this.
LOOP AT in_table2. "here in_table2 means table (an internal table)
WRITE / in_table2. "here in_table2 means the header of the table (a structure)
ENDLOOP.
Internal tables with headers should not be used exactly because of this confusion. Looks like you got confused exactly in such way. The meaning of in_table2 is ambiguous and depends on the context.
Better use field symbols for looping and appending.
FIELD-SYMBOLS: <fs_for_loop> LIKE LINE OF in_table2[].
LOOP AT in_table2[] ASSIGNING <fs_for_loop>.
WRITE / <fs_for_loop>.
ENDLOOP.

Related

Ada - Commando- line reader and processer

A program that loads and processes command-line arguments should be created.
Here comes a few examples on how it should look when you run it (bold text is the text that the user will type):
Terminal prompt % **./my_program**
No arguments given.
Terminal prompt % **./my_program 123**
Wrong amounts of arguments given.
Terminal prompt % **./my_program 10 XYZ 999 Greetings!**
Wrong amounts of arguments given.
Terminal prompt % **./my_program 3 HELLO**
Message: HELLOHELLOHELLO
The program "./my program" is ending.
Terminal prompt % **./my_program 0 Bye**
Message:
The program "./my program" is ending.
This is my code so far:
with Ada.Text_IO; use Ada.text_IO;
with Ada.Integer_Text_IO; use Ada.Integer_Text_IO;
with Ada.Command_Line; use Ada.Command_Line;
procedure my_program is
type String is array (Positive) of Character;
N : Integer;
Text : String;
begin
N := Argument_Count;
if N = 0 then
Put_Line("No arguments given.");
elsif N /= 2 then
Put_Line("Wrong number of arguments given.");
elsif N = 2 then
Put("Message: ");
for I in 1 .. N loop
Put(Text);
New_Line;
end loop;
Put("The program """);
Put(""" is ending. ");
end if;
end my_program;
My program handles the first 3 three cases but when I go ahead with the 4th and 5th (last) case I get an error code at the row Put(Text) where it says
Missing argument for parameter "Item" in call to "Put"
I don't know if I declared my string right because I don't want a string of a specific length. Can anyone come up with something that could help me solve case 4 and 5? It would be nice and highly appreciated
This seems to be a homework or exam question, so I would usually not provide a full answer. But Chris already gave that (with some defects), so here is my suggestion. Compared to Chris's solution, I try to avoid using unnecessary variables, and I favour case statements over if-then-else cascades, and I try to reduce the scope of exception handlers. I prefer to put use clauses in the subprogram so that the context-clause section contains only with clauses. I use the string-multiplying "*" operator from Ada.Strings.Fixed, but that is perhaps an unnecessary refinement.
with Ada.Command_Line;
with Ada.Strings.Fixed;
with Ada.Text_IO;
procedure My_Program
is
use Ada.Strings.Fixed;
use Ada.Text_IO;
begin
case Ada.Command_Line.Argument_Count is
when 0 =>
Put_Line ("No arguments given.");
when 2 =>
begin
Put_Line (
Natural'Value (Ada.Command_Line.Argument(1))
* Ada.Command_Line.Argument(2));
exception
when Constraint_Error =>
Put_Line ("Invalid input for argument 1.");
end;
when others =>
Put_Line ("Wrong amount of arguments given.");
end case;
Put_Line (
"The program """
& Ada.Command_Line.Command_Name
& """ is ending.");
end My_Program;
Note that my version:
Rejects negative first arguments (like "-3").
Outputs the repeated strings on a single line, as was required by the examples given.
Includes the name of the program in the final message, as was also required.
Given the clarification in comments as to the purpose of the program, to print a message n times where n is the first argument, and the message is the second argument, you need to parse the first argument as an integer. This can be done with Integer'Value.
Now, that raises the prospect of the user not running the program with an integer. So we have to handle the possible Constraint_Error exception.
with Ada.Text_IO; use Ada.text_IO;
with Ada.Integer_Text_IO; use Ada.Integer_Text_IO;
with Ada.Command_Line; use Ada.Command_Line;
procedure my_program is
argc : Integer;
N : Integer;
begin
argc := Argument_Count;
if argc = 0 then
Put_Line("No arguments given.");
elsif argc /= 2 then
Put_Line("Wrong number of arguments given.");
else
n := Integer'Value(Argument(1));
Put("Message: ");
for I in 1 .. N loop
Put_Line(Argument(2));
end loop;
Put("The program """);
Put(""" is ending. ");
end if;
exception
when Constraint_Error =>
Put_Line("Invalid input for argument 1.");
end my_program;
As an aside, when we've checked in our conditional if argc is zero, and that it doesn't equal two, we don't have to use elsif. The only other possibility is that it is 2.
You say
My program handles the first 3 three cases but when I go ahead with the 4th and 5th (last) case I get an error code at the row Put(Text) where it says "Missing argument for parameter "Item" in call to "Put". "
which doesn't make sense, because your program as shown doesn't compile. I guess what you mean is "when I try to add the code to handle cases 4 and 5, it doesn't compile".
The reason why it doesn’t compile is hidden in the actual error messages:
leun.adb:24:10: no candidate interpretations match the actuals:
leun.adb:24:10: missing argument for parameter "Item" in call to "put" declared at a-tiinio.ads:97, instance at a-inteio.ads:18
...
leun.adb:24:14: expected type "Standard.Integer"
leun.adb:24:14: found type "String" defined at line 7
leun.adb:24:14: ==> in call to "Put" at a-tiinio.ads:80, instance at a-inteio.
You have at line 7
type String is array (Positive) of Character;
which is both misleading and not what you meant.
It’s ’not what you meant’ because array (Positive) means an array of fixed length from 1 to Positive’Last, which will not fit into your computer’s memory. What you meant is array (Positive range <>).
Even with this correction, it's 'misleading' because although it would be textually the same as the declaration of the standard String in ARM 3.6.3(4), in Ada two different type declarations declare two different types. So, when you write Put(Text); the Put that you meant to call (the second in ARM A.10.7(16)) doesn’t match because it’s expecting a parameter of type Standard.String but Text is of type my_program.String.
Cure for this problem: don’t declare your own String type.

Conditional declaration by array of records

I try to create many components depending on the value of constant elements. These elements are organized in an array of records.
Dymola prints the translation log for the example below:
But I'm sure to use fixed conditions because I only perform allowed operations on constant values.
Here is the simple example of what I wantet to do:
model ConditionalComponent
type Enum = enumeration(one,two,three);
record Tmp
parameter Integer ID;
parameter Boolean active;
end Tmp;
record TmpNamed
parameter Enum name;
extends Tmp;
end TmpNamed;
function reorder
input TmpNamed inp[:];
output Tmp out[size(inp,1)];
algorithm
for elem in inp loop
out[elem.name] := Tmp(elem.ID, elem.active);
end for;
end reorder;
constant TmpNamed testIn[:] = {
TmpNamed(Enum.two,20,true),
TmpNamed(Enum.one,10,true),
TmpNamed(Enum.three,30,true)};
constant Tmp testOut1[:] = reorder({
TmpNamed(Enum.two,20,true),
TmpNamed(Enum.one,10,true),
TmpNamed(Enum.three,30,true)});
constant Tmp testOut2[:] = reorder(testIn);
constant Boolean active1 = testOut1[Enum.one].active;
constant Boolean active2 = testOut2[Enum.one].active;
Real t1=0 if testOut1[Enum.one].active;
//Real t2=0 if testOut2[Enum.one].active;
//Real t3=0 if active1;
//Real t4=0 if active2;
end ConditionalComponent;
The function reorder is intended to ease the management of large lists of named active components. Normally the constant testOut2 is used and created within the package ConditionalComponent. But for testing purposes ConditionalComponent is a model here. Actually I only want to use the line
Real t2=0 if testOut2[choice].active;
parameter Enum choice = Enum.one;
within other components, that have a parameter of type Enum. The declarations for t1, t3, t4 are only some tests that work, depending on what is left uncommented.
For example leaving the declaration for t1 and t3 uncommented works. But if one uses only the declaration for t1, it is not translated by Dymola.
The difference between t1 and t2 is, that the argument for reorder is passed directly or via the constant testIn.
I'm sure, that most parameter and constant prefixes are unnecessary and I tried hard to figure out the problem. But unfortunately I cannot decide whether Dymola is not working correctly or I did something wrong. And I've got no idea how to debug the translation process to figure it out by myself.
Can anyone tell me, what am I doing wrong?
Not something wrong, but it's just currently seen as too complicated and not handled.
A work-around is to split subscripting and element access:
constant Tmp testOut1_one=testOut1[Enum.one];
Real t1=0 if testOut1_one.active;

MatLab Map - Specified Key Type Not Matching Required

I'm attempting to make a program (for homework) which reads in a file, and then counts the number of times each word is used. For tackling the issue efficiently, I've decided to map all unique words to keys, and then increment the key value each time the word comes up.
function [] = problem2
file_open = fopen('austen.txt');
complete_string = textscan(file_open, '%s');
numel(complete_string{1,1})
unique_words = unique(complete_string{1,1});
length(unique_words);
frequency = zeros(numel(unique_words), 1);
found_frequency = containers.Map(unique_words, frequency);
for i=1:numel(complete_string{1,1})
found_frequency(complete_string{1,1}(i)) = found_frequency(complete_string{1,1}(i))+1;
end
fclose(file_open)
Sadly, this code does not work. When the line comes up to increment, I receive an error stating that "specified key type does not match the type expected for this container", which makes no sense to me - I'm using strings as the keys. Any ideas as to why I'm receiving this error?
The issue was in the use of Cell type - complete_String{1,1}(i) would actually return a Cell rather than a String (per spec, though). Wrapped it in char(*) and it worked fine.

Dynamic array or resize extend?

This is a superfluous question. Is there any dynamic array or list in Progress 10.2B?
Example:
I create a base class called "InventoryTransaction". I read a MSSQL table from Progress and I would like to create an instance of InventoryTransaction class for each record found then add it to a "list/array" so I can later process them.
Is there something like MyArray:Add(MyItem) that will increase automatically the array size +1 then will add the instance of MyItem to the array?
I discovered the function EXTENT to set a size dynamically to an array but I do not know the count before reading all the transaction in the MSSQL table. Alternatively, I could execute a "select count(*) from MyTable" before reading all the transaction to retrieve the count and then extent the array.
Thank you!
Happy friday!
Sebastien
You can create "indeterminate" arrays. i.e.
define variable x as decimal extent no-undo.
An indeterminate array variable can be in one of two states: fixed or unfixed, meaning it either has a fixed dimension or it does not. An indeterminate array variable has an unfixed dimension when first defined. You can fix the dimension of an indeterminate array variable by:
Initializing the array values when you define the variable,
Using the INITIAL option
Setting the number of elements in the array variable
Using the EXTENT statement
Assigning a determinate array to the indeterminate array, fixing it to the dimension of the determinate array
Passing array parameters to a procedure, user-defined function, or class-based method, so that the indeterminate array variable is the target for the passing of a determinate array, fixing the indeterminate array to the dimension of the determinate array
Once fixed, ABL treats a fixed indeterminate array as a determinate array.
I just discovered progress.lang.object:
FILE: array.p
/* declaration */
DEFINE TEMP-TABLE arrITem
FIELD Item AS CLASS PROGRESS.lang.OBJECT.
DEFINE VARIABLE oItem AS CLASS Item NO-UNDO.
DEFINE VARIABLE i AS INTEGER NO-UNDO.
/* create 10 products */
DO i = 1 TO 10:
CREATE arrItem.
arrItem.Item = NEW Item("Item_" + STRING(i), "Description_" + STRING(i)).
END.
/* display object information */
FOR EACH arrItem:
ASSIGN oItem = CAST(arrItem.Item,Item).
DISPLAY oItem:ItemNo.
END.
FILE: item.cls
CLASS Item:
DEFINE PUBLIC PROPERTY ItemNo AS CHARACTER
GET.
SET.
DEFINE PUBLIC PROPERTY DESCRIPTION AS CHARACTER
GET.
SET.
/* constructor */
CONSTRUCTOR PUBLIC Item():
END.
CONSTRUCTOR PUBLIC Item(
INPUT strItemNo AS CHARACTER
,INPUT strDescription AS CHARACTER
):
ASSIGN ItemNo = strItemNo.
ASSIGN DESCRIPTION = strDescription.
END.
END CLASS.
Thank you!
Sebastien
The short answer is - no, the 10.2B AVM doesn't allow you to dynamically resize an array.
The long answer is you could (a) add the object to a linked list of objects, or (b) create a temp-table with a Progress.Lang.Object field, create a new TT record for each object instance you want to track, and assign the object's pointer to the TT's PLO field.

MATLAB assign variable name

I have a variable called 'int' with alot of data in it. I would like to find a way to programically rename this variable with a user input. So I can query the user indentifcation information about the data, say the response is 'AA1', I want either rename the variable 'int' to 'AA1' or make 'AA1' a variable that is identical to int.
A problem using the input command arises because it allows the user to assign a value to an already created varialbe, instead of actually creating a variable name. Would using the eval function, or a variation of it, help me achieve this? Or is there an easier way?
Thanks!
Just for the record, int is a rather poor variable name choice.
That aside, you can do what you want as follows
say foo is the variable that holds a string that the user input. You can do the following:
% eliminate leading/trailing whitespace
foo = strtrim(foo);
a = regexp('[a-zA-Z][a-zA-Z0-9_]*',foo));
if numel(a) == 0
fprintf('Sorry, %s is not a valid variable name in matlab\n', foo);
elseif a ~= 1
fprintf('Sorry, %s is not a valid variable name in matlab\n', foo);
elseif 2 == exist(foo,'var')
fprintf('Sorry, %s already in use as a variable name.');
else
eval([foo,' = int']);
end
Assuming int (and now foo) is a structure with field named bar, you can read bar as follows:
barVal = eval([foo,'.bar']);
This is all somewhat clunky.
An alternative approach, that is far less clunky is to use an associative array, and let the user store various values of int in the array. The Matlab approach for associative arrays is Maps. That would be my preferred approach to this problem. Here is an example using the same variables as above.
nameValueMap = containers.Map;
nameValueMap(foo) = int;
The above creates the association between the name stored in foo with the data in the variable int.
To get at the data, you just do the following:
intValue = nameValueMap(foo);