Looping over characters in Fortran - loops

I would like to know if it is possible to loop over strings in Fortran. For example I would like to know if the following code:
DO p=a,b,c,t,r
...
END DO
would replace a b c t and r whenever a p is writen.

Or, if by string OP means a character variable of length n, one might have something like
character(len=n) :: string
...
string = 'abcdef'
...
do i = 1,n
write(*,*) string(i:i)
end do
noting that for taking substrings of any length (including 1) both start and end indices have to be supplied

A loop index is always a scalar integer. Fortunately it's a simple enough matter to use an array of the desired "iterated" objects:
character, parameter :: ps(*) = ['a', 'b', 'c', 't', 'r']
integer i
character p
do i=1, SIZE(ps)
p = ps(i)
...
end do
This idiom holds for more than just characters.

Related

Decimal to binary conversion in fortran

I am new in Fortran so I can't really evaluate where the semantic mistake is. From what I see the syntax is ok and when I build I don't see any mistake from the compiler I have in "Simply Fortran" I didn't find any standard function for binary conversion and I think there aren't any from what I see. Can anyone help me to fix the code so that I got displayed the elements of the array and the respective element in binary ? Thank you in advance for your help.
I think like this it works now.
I initialised the array with given numbers though.
code:
program array_binary
implicit none
integer, dimension(8) :: numbers
character(len=32), dimension(8) :: binary_numbers
integer :: i, j, k
numbers = [8, 9, 3, 4, 89, 6, 7, 8]
do i = 1, 8
write(*,*) numbers(i)
end do
do i = 1, 8
k = numbers(i)
binary_numbers(i) = ""
do j = 1, 32
if (mod(k,2) == 0) then
binary_numbers(i) = "0" // binary_numbers(i)
else
binary_numbers(i) = "1" // binary_numbers(i)
end if
k = k / 2
end do
end do
do i = 1, 8
write(*,*) binary_numbers(i)
end do
end program array_binary
I won't give you the solution, as it's better if you get it by yourself. However it looks like you have troubles with how arrays of strings work. Here is how:
character(len=32) :: string is a 32 characters string. You can access substrings with the : notation
string = "abcdef"
write(*,*) string ! full string
write(*,*) string(3:5) ! 3 characters substring
write(*,*) string(2:2) ! 1 character substring
! note that string(2) gives an error
string(1:3) = "ABC" ! write in a subtring
write(*,*) string
results in:
abcdef
cde
b
ABCdef
Now the arrays of string:
character(len=32) :: string(8) is a 8 elements arrays, each element being a 32 characters string. This is equivalent to
character(len=32), dimension(8) :: string
When indexing arrays of strings, the first index level refers to the array elements, and the second index level refers to the subtrings:
string(2) is the 2nd element of the array, and is a full 32 characters string. It is equivalent to string(2)(:)
string(2)(10:16) is a 7 characters substring of the 2nd element of the array
string(:)(10:10) is a 8 elements array of 1 character subtrings
string(4:6) is a 3 elements subarray of 32 characters strings

Polymorphic object fail when arrays are passed with arbitrary index range

I provide an example when converting a string to an integer array. I pass an array using an index range.The offset is being initiated by 0 rather than one, so the values in the array are being shifted.
s = "1,2,3,5,8"
Call str_to_num_tu (s, ",", tu(1:8))
$ Output:
$ tu(1): 0 ; tu(2): 1 ; tu(3): 2
Call str_to_num_tu (s, ",", tu)
$ Output:
$ tu(i): 1 ; tu(2): 2 ; tu(3): 3
Here is my subroutine using an unlimited polymorphic variable.
Subroutine str_to_num_tu &
( &
s, dl, tu, pos &
)
Class(*), Intent (InOut) :: tu(:)
Character (len=*), Intent (In) :: s, dl
Character (len=*), Intent (In), Optional :: pos
Integer, Allocatable :: ipos(:)
Integer :: nf, npos, ip, i, j, k
!!$ Sets tu.
!!$ s = "Pablo/Neruda"; tu = ["Pablo","Neruda"]
!!$ s = "0.2/1.3/1.5"; tu = [0.2,1.3,1.5]
nf = nfields (s, dl)
Write (*,*) ""
Write (*,*) "nf: ", nf, "; Size(tu): ", Size(tu)
i = 1
Do k = 1, nf-1
j = Index (s(i:), dl)
Select Type (tu)
Type Is (Integer (Int32))
Call str_to_num (s(i:i+j-2), tu(k))
Write (*,*) Trim (s(i:))
Write (*,*) "k: ", k, "; tu(k): ", tu(k)
End Select !!$ tu
i = i + j
End Do
!!$ Gets last field.
j = Index (s, dl, back=.true.)
Write (*,*) "j:", j, "; nf:", nf
Select Type (tu)
Type Is (Integer (Int32))
Call str_to_num (s(j+1:), tu(nf))
End Select !!$ tu
End Subroutine str_to_num_tu
To elaborate on my earlier comment. (I don't have Fortran on this computer so the syntax may be a little wonky.) What I meant is that something like this
integer, dimension(6), allocatable :: arr
integer :: ios
character(len=:), allocatable :: str
...
arr = 0
str = "1,2,3,5,8"
read(str,*,iostat=ios) arr
will read the first 6 integers from str into the elements of arr. As it happens str only has 5 integers so the last element of arr is left as 0. iostat is necessary here because an attempt to read more integers than str provides will otherwise produce an end-of-file error at run time.
Of course, this approach generalises to reals, characters and logicals too. Fortran has, built-in, polymorphic reading of intrinsic types. Up to a point.
Fortran will recognise blanks and spaces as value-separators (the Fortran standard uses the word delimiter to mean something else). Note that by setting the decimal mode on an i/o statement to comma Fortran will recognise the comma as a decimal point and treat a semi-colon, ;, as a value-separator. Technically a slash is also a value-separator but it also causes termination of list-directed input of the record so doesn't really act like a value-separator.
If concerned about strings containing other value-separators I might write a function which took a string containing such, returned one with only whitespace, and then perform the internal read on that.

How can I map a character to a pointer of another type?

I have a char*. I want to parse it, character by character, and store the location of each in an int*.
With the dummy-string "abbcdc", the content should be as follows
char int*
-------------
'a' -> 0
'b' -> 1,2
'c' -> 3,5
'd' -> 4
I want this to be accessible through a char* containing the entire alphabet, so that each character in the alphabet-pointer points to each separate integer-pointer. This is where I'm lost.
I know I can point to a pointer using the double-asterisk syntax
int **a = &aLocations;
But I don't really know how to refer to the locations-pointer by using a character as a reference. I am pretty new to C, so all pointers (pun intended) are appreciated.
Update 1:
int *aLocations = malloc(3*sizeof(int));
aLocations[0] = 13;
aLocations[1] = 9;
aLocations[2] = 57;
int **a = &aLocations;
This seems to work as expected, but a obviously remains an integer, not a char. I was thinking of writing a function something along the lines of
int *getCharLocations(char c) {
// returns a pointer to the stored character locations
}
but I don't know how to proceed with implementing it.
Ok then.
Although it would be possible it would be pretty ugly and complicated.
So if you do not mind i would suggest to drop char and use integers exclusively.
It is possible since char is in fact just small integer.
So first you would need to create your two dimensional alphabet array:
int *alphabet[26]; // this will create 26 element array of integer pointers
Now we will fill it:
int i = 0;
for(i = 0; i < 26; i++) {
alphabet[i] = malloc(100 * sizeof(int)); //alloc memory for 100 integers (should be enough for human language if we're talking about single words here)
alphabet[i][0] = 'a' + i; // this will put a letter as first element of the array
alphabet[i][1] = 2 // here we will keep index of first available position in our indices array
}
So now we have array like this:
'a', 2, ... // '...' means here that we have space to fill here
'b', 2, ...
...
'z', 2, ...
And you can add indices of occurences of letter to such construction like this:
alphabet[index_of_letter][alphanet[index_of_letter][1]] = index_of_letter; //put index at the end of array
alphabet[index_of_letter][1]++; // increment our index of available position
That's pretty much it.
I didn't test it so it may need some polishing but such approach should do the trick.
PS.
Someone in comments above noted uppercase letters - in such case you would need to extend array to 52 characters to store also occurences of uppercase letters (also fill first element with uppercase letter in for loop for such records). But i guess you will manage from now on

Access structure array whose index is stored in a string

I want to get a value from a structure array by code, and I'll have the index stored in a string.
I've tried to run this code:
function M = getdata(matrix,field,varargin)
exp = [];
for i = 1:nargin-3
exp = [exp num2str(varargin{i}) ','];
end
exp = [exp num2str(varargin{nargin-2})];
M = eval('matrix(exp).(Field)');
end
However, it fails.
For example, suppose I have a structure array with 2 fields, A and B. So, I could write
MyStruct(1,1).A
A possible use would be:
M = getdata(MyStruct,A,1,1)
and I want the program to do:
M = MyStruct(1,1).A
How could I do that?
Thanks!
You can use the getfield function:
M = getfield(MyStruct, {1,1} ,'A');
Or if you wanted, say, MyStruct(1,1).A(3).B:
M = getfield(MyStruct, {1,1}, 'A', {3},'B');
For the example you give, this will suffice:
function M = getdata(matrix,field,varargin)
M = matrix(varargin{:}).(field);
which you call like
getdata(myStruct, 'A', 1,1)
which makes that function pretty useless.
But, in general, when you have indices given as strings, you can follow roughly the same approach:
%// Your indices
str = {'1', '2'};
%// convert to numbers
str = cellfun(#str2double, str, 'UniformOutput', false);
%// use them as indices into structure
M = myStruct(str{:}).(field)
And if you really insist, your call to eval is just wrong:
M = eval(['matrix(' exp ').(' field ')']);
And, as a general remark, please refrain from using exp as the name of a variable; it is also the name of a built-in function (the natural exponential function).

How can I randomize a sequence of characters?

I want to write a function which randomizes the order of a sequence of alphabetic characters. For example, the sequence:
A B C D E F G . . .
...might be changed to:
Z L T A P ...
...which, if passed to the same function again could result in:
H R E I C ....
Any suggestions?
Have a look at the Fisher-Yates shuffle algorithm, and in particular the modern version of it.
This sounds like homework, but either way:
http://stanford.edu/~blp/writings/clc/shuffle.html
You mean randomise the alphabet? I wrote something similar in PHP a few days ago. The logic was the following:
Let S1 be a string containing the alphabet characters "ABC...XYZ".
Let S2 be an empty string.
While strlen(S1) > 0, choose a random character C from S1. Append C to S2 and remove C from S1.
Return S2.
The result is a randomly shuffled set of characters, created with minimal CPU load (if the string has 26 characters, the inner loop only needs 26 iterations).

Resources