guezo
guezo

Reputation: 21

Using an implied do-loop to initialize a character array

Can I replace an explicit initialization of a character array, like this:

character(len=8), dimension(5) :: names  = (/'ens_0001','ens_0002','ens_0003','ens_0004','ens_0005'/)

with an implied do-loop construct? Something with a formatted write statement?

character(len=8), dimension(5) :: names  =  write? other magic? 'ens_',i4.4', ... (/j=1,5/) 

Upvotes: 2

Views: 155

Answers (2)

francescalus
francescalus

Reputation: 32396

The question is essentially equivalent to the alternative question: can I convert an integer to a character in a constant expression?

Yes you can, but you are limited in how this can be done.

One way would be:

  implicit none

  character, parameter :: digit(0:*) = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9']
  integer i  
  character :: number(3) = [(digit(i), i=2, 8, 3)]

  print '(A)', number
end

And there are other ways, such as using ACHAR.


Once you know how to get a single character you can use the natural extensions, such as

  character(8) :: label(5) = 'ens_000'//[(digit(i), i=1, 5)]

And so on, extending to tens, hundreds and more if you find the appropriate logic:

  integer j
  character(2), parameter :: twodigit(0:*) = [((digit(i)//digit(j), j=0,9), i=0,9)]
 
  character(8) :: label(12) = 'ens_0'//[(twodigit(i), i=11, 22)]

You cannot use an internal write (or other executable statement) or a user-defined function in the constant expression.

This does quickly become silly as the number of digits increases, but it's also possible to use indexes (or substrings) and arithmetic:

  character(8) :: label(12) = 'ens_0'//[(digit(i/10)//digit(mod(i,10)), i=11, 22)]

(Recall if using them that substrings are always 1-indexed.)

Upvotes: 3

guezo
guezo

Reputation: 21

Thanks Francescalus for the pointers! That really helped. The final solution is posted below. I never actually stated this detail, but I had to go from ens_0001 to ens_1200, so the nested implicit do-loops are 4 deep!

program foo
  implicit none

  integer i,j,k,l
  character, parameter :: digit(0:*) = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9']
  character(4), parameter :: fourdigit(0:*) = [((((digit(i)//digit(j)//digit(k)//digit(l), l=0,9), k=0,9), j=0,9), i=0,9)]

  character(8) :: label(1200) = 'ens_'//[(fourdigit(i), i=1, 1200)]
  print '(A)', label
end

Upvotes: 0

Related Questions