Format reversion to print comma-separated matrix elements

Here’s a small program that prints a 3x4 complex matrix with a preamble, surrounds each row with square brackets, and uses a repeat count to print the elements of each row. It uses format reversion to print each row on a separate line without repeating the preamble.

implicit none

complex, dimension(3,4) :: a = reshape(cmplx([1,2,3,4,5,6,7,8,9,10,11,12]),[3,4],order=[2,1])
integer :: i

a = a + (0.0,1.0)

print *
print '("Here''s the matrix with format 1:",/,("[",1x,4(S,G0,SP,G0,"i",1x),"]"))', (a(i,:), i=1,3)
print *
print '("Here''s the matrix with format 2:",/,("[",1x,4(s,g0,sp,g0,"i",",",1x),"]"))', (a(i,:), i=1,3)
print *

end
Result with gfortran 9.4.0
Here's the matrix with format 1:
[ 1.00000000+1.00000000i 2.00000000+1.00000000i 3.00000000+1.00000000i 4.00000000+1.00000000i ]
[ 5.00000000+1.00000000i 6.00000000+1.00000000i 7.00000000+1.00000000i 8.00000000+1.00000000i ]
[ 9.00000000+1.00000000i 10.0000000+1.00000000i 11.0000000+1.00000000i 12.0000000+1.00000000i ]

Here's the matrix with format 2:
[ 1.00000000+1.00000000i, 2.00000000+1.00000000i, 3.00000000+1.00000000i, 4.00000000+1.00000000i, ]
[ 5.00000000+1.00000000i, 6.00000000+1.00000000i, 7.00000000+1.00000000i, 8.00000000+1.00000000i, ]
[ 9.00000000+1.00000000i, 10.0000000+1.00000000i, 11.0000000+1.00000000i, 12.0000000+1.00000000i, ]

In the first instance the elements are separated by spaces. In the second instance I added comma separators, but I’m wondering how to omit the comma after the last element of each row. A : within the repeated segment only terminates the final reversion, and omits the final comma and ending bracket on the last row only. Is there a way to do this without manually splitting out the last repetition?

You can use the colon edit descriptor to suppress the comma after the last value and use an unlimited format item with * to print an unlimited number of values instead of hard-coding the number to be printed. Since you want a final bracket you will use `advance=“no” prior to it. The program

implicit none
integer :: v(3) = [1, 4, 9]
write (*,"(*(i0,','))") v
write (*,"(*(i0,:,','))") v
write (*,"('[',*(i0,:,','))", advance="no") v
write (*,"(']')")
end

gives

1,4,9,
1,4,9
[1,4,9]

I don’t believe this works for matrices with multiple rows. The comma will be printed after the last value in each row, and the bracket will only appear after the last row.

I know there are ways to assemble what I want using multiple write statements in a do loop using advance=no. I should have been more specific that I’m curious if there’s a one-line format that can do it.

I would use the advance='no' approach shown by @Beliavsky, but for a 2D array you will need to print each row separately (with an actual do loop, not an implied do loop).

Another general approach would be to build the appropriate character format string specifically for the given column dimension. That allows you to print using a single print/write statement and with the implied do-loop, as in your original code, so there is a tradeoff. I think the advance='no' approach is simpler and easier to understand, in case you or someone else needs to modify the output in the future. I doubt there is any difference in runtime efficiency between these two approaches.

Although you look to be exploring Fortran descriptor language, others looking for a ready-made solution for printing small matrices might like
M_display, particularly if they are using fpm. An example of basic usage:

program reversion
use M_display, only : disp
implicit none

complex, dimension(3,4) :: a = reshape(cmplx([1,2,3,4,5,6,7,8,9,10,11,12],1),shape(a),order=[2,1])

call disp("Here's the matrix with format 1:",a,sep=',',style='above')
print *
call disp("Here's the matrix with format 2:",a,style='underline & number')
print *
call disp("Here's the matrix with format 3:",a,fmt='f4.1',fmt_imag='f4.1',sep=',',style='above')

end program reversion

Output

                     Here's the matrix with format 1:                     
1.0000 + 1.00000i, 2.0000 + 1.00000i, 3.0000 + 1.00000i, 4.0000 + 1.00000i
5.0000 + 1.00000i, 6.0000 + 1.00000i, 7.0000 + 1.00000i, 8.0000 + 1.00000i
9.0000 + 1.00000i,10.0000 + 1.00000i,11.0000 + 1.00000i,12.0000 + 1.00000i

                        Here's the matrix with format 2:                        
--------------------------------------------------------------------------------
           1                   2                   3                   4        
1  1.0000 + 1.00000i   2.0000 + 1.00000i   3.0000 + 1.00000i   4.0000 + 1.00000i
2  5.0000 + 1.00000i   6.0000 + 1.00000i   7.0000 + 1.00000i   8.0000 + 1.00000i
3  9.0000 + 1.00000i  10.0000 + 1.00000i  11.0000 + 1.00000i  12.0000 + 1.00000i

          Here's the matrix with format 3:         
 1.0 +  1.0i, 2.0 +  1.0i, 3.0 +  1.0i, 4.0 +  1.0i
 5.0 +  1.0i, 6.0 +  1.0i, 7.0 +  1.0i, 8.0 +  1.0i
 9.0 +  1.0i,10.0 +  1.0i,11.0 +  1.0i,12.0 +  1.0i
2 Likes

Here’s what this looks like:

implicit none

complex, dimension(3,4) :: a = reshape(cmplx([1,2,3,4,5,6,7,8,9,10,11,12]),[3,4],order=[2,1])
integer :: i
character(len=2) :: adim2

a = a + (0.0,1.0)

write(adim2,'(i0)') size(a,2)-1
print *
print '("Here''s the matrix with format 3:",/,("[",1x,'//adim2//'(S,G0,SP,G0,"i,",1x),(S,G0,SP,G0,"i",1x),"]"))',&
       (a(i,:), i=1,size(a,1))
print *

end

Almost as compact.

Results:

Here's the matrix with format 3:
[ 1.00000000+1.00000000i, 2.00000000+1.00000000i, 3.00000000+1.00000000i, 4.00000000+1.00000000i ]
[ 5.00000000+1.00000000i, 6.00000000+1.00000000i, 7.00000000+1.00000000i, 8.00000000+1.00000000i ]
[ 9.00000000+1.00000000i, 10.0000000+1.00000000i, 11.0000000+1.00000000i, 12.0000000+1.00000000i ]