How to write structures? - abap

How can I show the value inside a structure? see below the example:
DATA: BEGIN OF line,
col1 TYPE i,
col2 TYPE i,
END OF line.
DATA: itab LIKE TABLE OF line,
jtab LIKE TABLE OF line.
DO 3 TIMES.
line-col1 = sy-index.
line-col2 = sy-index ** 2.
APPEND line TO itab.
ENDDO.
MOVE itab TO jtab.
line-col1 = 10. line-col2 = 20.
APPEND line TO itab.
IF itab GT jtab.
WRITE / 'ITAB GT JTAB'.
ENDIF.
Write: itab, jtab.
because i want to know why itab is greater than jtab?.

If you want to see the contents of a field purely for debugging purposes you can also just put a break point in your code and look at the contents in debugger.
Just don't leave the break point in productive code!
break-point.
"or use break yourusername <= this use is safer
EDIT:
You can also just use a session break-point, which does not require you to change the code (and will only be applicable to your user for the duration of the session):
In the system where you are running the program:
Open the Program
Select the line that you would like the program to stop on
Click the session Break-point button
The break-point icon will appear next to the line (you can also just click in the place where the icon appeared, to set/delete the break-point).

I assume that this is just a quick example and you don't want to use (parts of) this in a productive environment - so I ignore the other potential issues there are in your code.
Down to your question, you need to loop over your itab to access its values. You can then access a value like so:
DATA: ls_current_line LIKE line.
" ...
LOOP AT itab INTO ls_current_line.
WRITE / ls_current_line-col1.
ENDLOOP.

You could use function module REUSE_ALV_GRID_DISPLAY.
For example:
CALL FUNCTION 'REUSE_ALV_GRID_DISPLAY'
TABLES
t_outtab = itab.

ITAB is greater than JTAB because it contains more lines; ITAB has 4 lines while JTAB has 3 lines.
When it comes to internal tables, the GT operator first takes a look at the number of lines in the tables. More details on the comparison operators (for internal tables) can be found at http://help.sap.com/saphelp_nw04/helpdata/en/fc/eb3841358411d1829f0000e829fbfe/content.htm. [I see that your example is also taken from this help page.]

Related

I would like to MOVE just one line in Vim

yy and p should copy and paste 1 line of text.
But I have to go back and delete the original line.
:2,5m10
should move lines from 2 to 5 to line 10. however I need to enable :set number
to see what lines I am moving
I would like to move just 1 line of text, sort of like yy+p and not use :2,3m10
to move just one line.
Is there something like mm+p ?
so it copies the current line into buffer and deletes the line and you p paste it where you want ?
:3m . moves line 3 to your current line.
Above line does the function I want. Can I set a key mapping so
that "mm" replaces ":3m." ? I find it easier to type. TIA
What you're describing is the default behaviour when using dd -it deletes a
line into the buffer and p will paste it.
So dd and p works.
If you're new to vim, then it might seem a little strange that 'yanking' (with
y) and 'deleting' (with d) both copy to the buffer, given the 'cut', 'copy'
and 'paste' behaviours of most other editors.
You can read more about it with :help change.txt and in particular :help registers.
Also, since you say you need to enable :set number, I wonder if you've come
across :set relativenumber? This is very useful - in the example below, the
numbers would look this way if the your cursor was on the line with
'demonstrate':
3 This is just
2 a small
1 example to
0 demonstrate
1 how relative
2 numbers can
3 be useful
Thus if you wanted to move the line 'a small' below the line with 'numbers
can', you could use the relative line numbers to know that 2k would put the
cursor on the line you want, where you'd hit dd, then you'd have this
situation (the deleted line is now in the buffer:
1 This is just
0 example to
1 demonstrate
2 how relative
3 numbers can
4 be useful
Then you can do 3j to move to the 'numbers can' line, and hit p. So
relative numbers are a nice way to move quickly to lines you can see. Also,
just for completeness, you can use relative numbers in a similar way on the
command line::-2m+3 (although I know this isn't what you're after). You can
even set both relative number and set number at the same time, in which case
it's like in the example above, only you have the absolute line number
displayed on the current line instead of a zero.

Check structure fields for being non-initial?

I need to fetch records from csv file and process it. Initially I need to check if all the values are there or not (around 15 fields), if the value is initial (i.e. blank) I need to throw the error (output has to be written in a file for each record).
Current logic I am following is :
LOOP AT gt_filedata into gs_filedata.
IF gs_filedata-var1 IS INITIAL.
concatenate gv_msg text-001 into gv_msg SEPARATED BY ','.
ENDIF.
IF gs_filedata-var2 IS INITIAL.
concatenate gv_msg text-002 into gv_msg SEPARATED BY ','.
ENDIF.
" And so on...
ENDLOOP.
I need to know if there any function module or any other way to optimize my code and improve its performance.
Assuming, as your code indicates, that you want to produce, not to fetch (as you wrote) a csv line:
field-symbols: <lv_part> type any,
<ls_filedata> like line of gt_filedata.
data: lv_part type string,
lv_msg type string.
loop at gt_filedata assigning <ls_filedata>.
clear lv_msg.
do.
assign component sy-index of structure <ls_filedata> to <lv_part>.
if sy-subrc ne 0.
exit. " exit DO
endif.
if <lv_part> is not initial.
lv_part = <lv_part>. " Converts to type C
if lv_msg is not initial.
concatenate lv_msg ',' into lv_msg.
endif.
concatenate lv_msg lv_part into lv_msg.
endif.
enddo.
append lv_msg to lt_csv. " Or transfer line to output file here
endloop.
If you want not to check each workarea field via IF, you should read the dd03 from the type of the workarea. Then you need some hard coded strings, which partially identify those fields in the workarea. Then you need an inner loop where you loop over the dd03 workarea, with a "contains pattern" instruction previously, which guarantees, that You loop only over the relevant field names of the dd03. Then you need assign-component (inner loop over dd03l-fieldnameof-actual looped field) of structure YourWorkarea to <anyfieldsymbol>, which you created before.
If you use "casting" afterwards you can use rollname to cast the actual looped field to rollname which is a part of dd03l. This quarantees that a fieldsymbol typed by "any" can properly be filled and therefore checked for being initial more precisely.
Do you need some code? Here it is:
Define some variables:
lo_structdesc TYPE REF TO cl_abap_structdescr,
dfies_wa TYPE dfies,
dfies_tab TYPE STANDARD TABLE OF dfies,
lv_ident TYPE fieldname value 'INP_'. " imagine all fields start like this.
FIELD-SYMBOLS: <fsany> TYPE any.
FIELD-SYMBOLS: <fsanyv> TYPE any
Imagine you want to get the datatype of Your workarea ( there are several ways):
" get struct by type
lo_structdesc ?= cl_abap_structdescr=>describe_by_data( my_struct ).
" introspect components
dfies_tab = lo_structdesc->GET_DDIC_FIELD_LIST( ).
loop at dfies_tab into dfies_wa where fieldname cp lv_ident.
assign-component ( dfies_wa-fieldname ) of structure my_struct to <fsany> casting type (dfies_wa-rollname).
if <fsany> is assigned.
if <fsany> is initial.
" ERROR HERE
else.
" continue with loop.
endif.
endif.
endloop.
Untested shrunk copy out of my source for dynamic where statement creation, cut down to the most fitting parts, removed overhead, so untested.

Cannot print subsequent rows of array to file

I'm trying to write a rudimentary bit of code to print a 50*50 array called 'arr'. Unfortunately it so far only prints the first row of the array, although the formatting for that row is correct. I've attached the code below and was wondering if anyone could point out where I was going wrong? Thank you!
program testing
implicit none
integer :: i, j
integer, dimension (1:50, 1:50) :: arr
arr = 1
do i=1,50
open(unit=6, file= "array.txt", action="write")
write(6, '(2500I3)') (arr(i,j), j=1,50)
close(6)
end do
end program testing
Your open statement is inside loop (along with a matching close statement). That means for every row of the array, you open the file. That's probably not what you meant to do.
The default position specifier for an OPEN statement if there is no POSITION specifier is 'ASIS'. For a file that already exists (your case after the first iteration, and perhaps even for the first iteration) that means that the position is unspecified. Your processor probably takes that to be the start of the file. That means that each iteration of the loop you simply overwrite the first record, over and over again.
If you must open the file each iteration, then use the POSITION='APPEND' specifier to position the file at the end when the open statement is executed. Otherwise, move the open and close statements out of the loop.
(The way that the default of 'ASIS' behaves means that you should always specify the initial position of a file via a POSITION specifier when executing an OPEN statement for an existing "on disk" file.)
IanH's answer is correct. Your program can be fixed as follows. Note that output units should be parameterized and not set to 6 and that arrays and array sections can be written as shown.
program testing
implicit none
integer :: i
integer, dimension (1:50, 1:50) :: arr
integer, parameter :: outu = 20 ! better to parameterize unit and
! not to use the number 6, which most compilers
! use for standard output
arr = 1
open(unit=outu, file= "array.txt", action="write")
do i=1,50
write(outu, '(2500I3)') arr(i,:) ! can write array section without implied do loop
end do
close(outu)
end program testing

Read text file line by line but only specific columns

How do we read a specific file line by line while skipping some columns in it?
For example, I have a text file which has data, sorted out in 5 columns, but I need to read only two columns out of it, they can be first two or any other random combination (I mean, need a solution which would work with any combination of columns like first and third only).
Code something like this
open(1, file=data_file)
read (1,*) ! to skip first line, with metadata
lmax = 0
do while (.true.)
! read column 1 and 3 here, either write
! that to an array or just loop through each row
end do
99 continue
close (1)
Any explanation or example would help a lot.
High Performance Mark's answer gives the essentials of simple selective column reading: one still reads the column but transfers it to a then-ignored variable.
To extend that answer, then, consider that we want to read the second and fourth columns of a five-column line:
read(*,*) junk, x, junk, y
The first value is transferred into junk, then the second into x, then the third (replacing the one just acquired a moment ago) into junk and finally the fourth into y. The fifth is ignored because we've run out of input items and the transfer statement terminates (and the next read in a loop will go to the next record).
Of course, this is fine when we know it's those columns we want. Let's generalize to when we don't know in advance:
integer col1, col2 ! The columns we require, defined somehow (assume col1<col2)
<type>, dimension(nrows) :: x, y, junk(3) ! For the number of rows
integer i
do i=1,nrows
read(*,*) junk(:col1-1), x(i), junk(:col2-col1-1), y(i)
end do
Here, we transfer a number of values (which may be zero) up to just before the first column of interest, then the value of interest. After that, more to-be-ignored values (possibly zero), then the final value of interest. The rest of the row is skipped.
This is still very basic and avoids many potential complications in requirements. To some extent, it's such a basic approach one may as well just consider:
do i=1,nrows
read(*,*) allofthem(:5)
x(i) = allofthem(col1)
y(i) = allofthem(col2)
end do
(where that variable is a row-by-row temporary) but variety and options are good.
This is very easy. You simply read 5 variables from each line and ignore the ones you have no further use for. Something like
do i = 1, 100
read(*,*) a(i), b, c(i), d, e
end do
This will overwrite the values in b, d, and e at every iteration.
Incidentally, your line
99 continue
is redundant; it's not used as the closing line for the do loop and you're not branching to it from anywhere else. If you are branching to it from unseen code you could just attach the label 99 to the next line and delete the continue statement. Generally, continue is redundant in modern Fortran; specifically it seems redundant in your code.

Fortran, How do I get Fortran to ignore lines from a data file that has random spacing

I am writing a FORTRAN code that uses data in a file made by a MD program. the data is a list of values but has breaks in the data for list updates in the form (# Neighbor list update .. 6527 indexes in list), These breaks are at random intervals so I can't just skip every x
I when I do my code it doesn't ignore these lines and randomly adds the value from the previous step.
1, 0.98510699999999995, 0.98510699999999995
2, 1.9654170000000000, 0.98031000000000001
3, 2.9427820000000002, 0.97736500000000004
4, 3.9186540000000001, 0.97587199999999996
4, 4.8945259999999999, 0.97587199999999996
5, 5.8697910000000002, 0.97526500000000005
note the double step 4 with an identical value from the true step 4
How would I go about skipping this line. Please find the sample code below
Open(Unit=10,File='prod._100.tup')
do i=1,50
Read(10,*,IOSTAT=ios)step,temp,kinetic,potential,total,pressure
If(IS_IOSTAT_END(ios)) Exit
test=test+temp
print*, step, test, temp
End Do
It is not clear to me what the "breaks" in the file are. Are they blank lines? If so, the following code should work:
use, intrinsic :: iso_fortran_env
character (len=200) :: line
Open(Unit=10,File='prod._100.tup')
read_loop: do
Read (10,'(A)',IOSTAT=ios) line
If(ios == iostat_end) exit read_loop
if (len_trim (line) == 0) then
write (*, *) "blank line"
cycle read_loop
end if
read (line, *) step,temp,kinetic,potential,total,pressure
test=test+temp
print*, step, test, temp
end do: read_loop
write (*, *) "total is", test
The above is not tested. The "len_trim" test is based on bad records being blank lines. If breaks are otherwise defined you will have to create a different test.
Try:
i=1
do while (i<=50)
Read(10,*,IOSTAT=ios)step,temp,kinetic,potential,total,pressure
If(IS_IOSTAT_END(ios)) Exit
IF(ios.ne.0) cycle
test=test+temp
i=i+1
enddo
When a bad record is read, ios is assigned a system dependent non-zero number (it is zero on success). Apparently you've written a function (IS_IOSTAT_END) to tell if you've reached the end of the file, but other error conditions can exist (for example, the read statement doesn't match the data). That will return a different non-zero ios than an end-file record, so you should just restart the loop at that point (e.g. cycle)
I assume you want to read exactly 50 lines from the file, so I changed your do loop to a do while, but if the number of records you read doesn't actually matter, then feel free to change it back.