Loop in Fortran from a list - loops

I use Fortran and I was wondering if it's possible to make something like that
do i = array
write (*,*) i
end do
where array is a list of integer numbers not necessarily ordered.

I would introduce a second index to iterate over the elements of an array:
program test
implicit none
integer, dimension(6) :: A
integer, dimension(10) :: B
integer :: i, j
A = (/ 1, 3, 4, 5, 8, 9 /)
B = (/ 2, 4, 6, 8, 10, 12, 14, 16, 18, 20 /)
do j = 1, size(A)
i = A(j)
write(*,*) i, B(i)
end do
end program test

Do you mean that you want to write some of the elements of an array called other_array but not all of them, and that i should take, essentially, arbitrary values in turn ? In other words you want to print not
do i = 1, size(other_array,1)
write(*,*) other_array(i)
end do
but something like
array = [1,3,4,2,3,7,8,8,12]
write(*,*) another_array(array)
which will write the elements of another_array specified in array ? This is called array subscripting. I haven't tested this and I'm heading out now so won't.

Related

Is there a way to assign values to a multidimensional array in Fortran without using nested loops? [duplicate]

In C you can easily initialize an array using the curly braces syntax, if I remember correctly:
int* a = new int[] { 1, 2, 3, 4 };
How can you do the same in Fortran for two-dimensional arrays when you wish to initialize a matrix with specific test values for mathematical purposes? (Without having to doubly index every element on separate statements)
The array is either defined by
real, dimension(3, 3) :: a
or
real, dimension(:), allocatable :: a
You can do that using reshape and shape intrinsics. Something like:
INTEGER, DIMENSION(3, 3) :: array
array = reshape((/ 1, 2, 3, 4, 5, 6, 7, 8, 9 /), shape(array))
But remember the column-major order. The array will be
1 4 7
2 5 8
3 6 9
after reshaping.
So to get:
1 2 3
4 5 6
7 8 9
you also need transpose intrinsic:
array = transpose(reshape((/ 1, 2, 3, 4, 5, 6, 7, 8, 9 /), shape(array)))
For more general example (allocatable 2D array with different dimensions), one needs size intrinsic:
PROGRAM main
IMPLICIT NONE
INTEGER, DIMENSION(:, :), ALLOCATABLE :: array
ALLOCATE (array(2, 3))
array = transpose(reshape((/ 1, 2, 3, 4, 5, 6 /), &
(/ size(array, 2), size(array, 1) /)))
DEALLOCATE (array)
END PROGRAM main
For multidimensional (rank>1) arrays, the Fortran way for initialization differs from the C solution because in C multidimensional arrays are just arrays of arrays of etc.
In Fortran, each rank corresponds to a different attribute of the modified data type. But there is only one array constructor, for rank-1 arrays. From these two reasons, initialization through array constructor requires the RESHAPE intrisic function.
In addition to what has already been answered, there is a more direct way of entering the value of a matrix by row instead as by column: reshape has an optional argument ORDER which can be used to modify the order of filling the element of the multidimensional array with the entries of the array constructor.
For instance, in the case of the example in the first answer, one could write:
INTEGER, DIMENSION(3, 3) :: array=reshape( (/ 1, 2, 3, &
4, 5, 6, &
7, 8, 9 /), &
shape(array), order=(/2,1/) )
obtaining the filling of the matrix array exactly in the order shown by the lines of code.
The array (/2, 1/) forces the column index (2) to have precedence on the row index (1), giving the desired effect.
Array initialization can be done in the array declaration statement itself, as shown below:
program test
real:: x(3) = (/1,2,3/)
real:: y(3,3) = reshape((/1,2,3,4,5,6,7,8,9/), (/3,3/))
integer:: i(3,2,2) = reshape((/1,2,3,4,5,6,7,8,9,10,11,12/), (/3,2,2/))
end program test
It surprises me that
real:: y(3,3) = (/(/1,2,3/),(/4,5,6/),(/7,8,9/)/)
is not accepted by the compiler (tried g95, gfortran). It turns out that the shape of
(/(/1,2,3/),(/4,5,6/),(/7,8,9/)/) is 9 and not 3 3!

remove all negative elements from an array buffer of integers in scala

I have a question about coding. There are similar types of questions in the database which I came across but none of them clears my doubt. I am going thru the book of "Scala for Impatient". The code below removes negative elements from the Array and gives positive elements as output
val a = ArrayBuffer(-1, 1, 0, -2, -1, 2, 5, 6, 7)
val positionsToKeep = for (i <- a.indices if a(i) >= 0) yield i
for (j <- positionsToKeep.indices) a(j) = a(positionsToKeep(j))
a.trimEnd(a.length - positionsToKeep.length)
It gives the output as (1,0,2,5,6,7) removing all negative elements.
I am unable to understand line 3 & 4.
for (j <- positionsToKeep.indices) a(j) = a(positionsToKeep(j))
a.trimEnd(a.length - positionsToKeep.length)
I'm scratching my head since 2 days on these 2 lines but can't give up and I finally posting it here seeking some help.
As a is a bufferArray so we can change the values of the array a.
Line 3:
Line 3 is populating or you can say updating the value of positionToKeep into a.
a(j) = positionToKeep(j)
// which is running like this
// a(0) = positionToKeep(0)
// a(1) = positionToKeep(1) .... and so on
Now what will happen after populating all the values of positionToKeep into a there might be the case some older values remains untouched. Line four is deleting or dropping these elements. In the case when we have all the positive values in array a line four has like no use but when the length of a is greater then positionToKeep then we need line 4.
Line 4: consider the scenario
val a = Array(1, 2, 3, 4, 5, 6)
Then our positionToKeep will have all the element and the length of both the array will be equal.
val positionToKeep = Array(1, 2, 3, 4, 5, 6)
In this case line four trimEnd(0) because length of a and positionToKeep are equal.
val a = Array( 1, 2, 3, 4, -5, -6, 8, 9, -3)
In this case we will have Array(1,2,3,4,8,9) in positionToKeep
In line 3 we will update array a and after updating before line four this is how our array a will look like.
Array(1,2,3,4,8,9,8,9,-3) as we need values only up to length 6 as we have only 6 positive values. We need to drop last 3 element that what is tripEnd doing for us.

Separating a matrix into sub-matrices in Fortran

Suppose I have a 2-D array such that the first column is composed of only two integers 1 and 2:
1 5 1 7 0.5
2 4 5 6 0.1
1 9 3 4 0.6
2 8 7 2 0.2
I want to separate two matrices out of this, such that the first column of each contains the same integer (so the first column of first matrix contains only integer 1, same goes for 2 in the second matrix).
So it would become:
1 5 1 7 0.5
1 9 3 4 0.6
and
2 4 5 6 0.1
2 8 7 2 0.2
I don't know exactly how to start. I was thinking of using the count at the beginning (well, because I have a way larger matrix with 10 different integers in the first column), then according to the counted number of each integer I construct the dimension of each [sub]matrix. After that, the only thing I could think of is the count(mask), and if the value is true it's then added to the matrix by if statement.
You can't have mixed types (integer and real) in the same array in Fortran, so I will suppose all data are real in the 2-dim array:
program split
implicit none
real, allocatable :: a(:, :), b(:, :)
integer :: i, ids = 10
integer, allocatable :: id(:), seq(:)
a = reshape([real :: 1, 5, 1, 7, 0.5, &
& 2, 4, 5, 6, 0.1, &
& 1, 9, 3, 4, 0.6, &
& 2, 8, 7, 2, 0.2], [5, 4])
seq = [(i, i = 1, size(a, 2))]
do i = 1, ids
print*, "i = ", i
! here we are creating a vector with all the line indices that start with i
! e.g. for i = 1 we get id = [1, 3], for i = 2 we get [2, 4], for i = 3 we get [], ...
id = pack(seq, a(1,:) == i)
! here we use a Fortran feature named vector-subscript
b = a(:, id)
print*, b
end do
end
If you want the first column(or any column) to be integer, you can declare it as a separated array, and use the same vector subscripts to gather the desired lines.

Broadcast array multiplication in Fortran 90/95

I was wondering that would there be a better (succinct) way to code this in Fortran? I am trying to multiply each column of a(3, 3) by each value in b(3). I know in Python there is np.multiply, and not sure about Fortran.
!!! test.f90
program test
implicit none
integer, parameter :: dp=kind(0.d0)
real(dp) :: a(3, 3)=reshape([1, 2, 3, 4, 5, 6, 7, 8, 9], [3, 3]),&
b(3)=[1, 2, 3]
integer :: i
do i = 1, 3
a(:, i) = a(:, i) * b(i)
end do
write(*, *) a
end program test
Thanks in advance!
The expression
a * SPREAD(b,1,3)
will produce the same result as your loop. I'll leave it to you and to others to judge whether this is more succinct or in any way better than the loop.
The do loop can be replaced by a one-liner using FORALL:
forall (i=1:3) a(:, i) = a(:, i) * b(i)
If you are reusing a particular b frequently you could define:
b(3, 3)=reshape([1, 1, 1, 2, 2, 2, 3, 3, 3], [3, 3])
then you just can do:
a=a*b
..

How to initialize two-dimensional arrays in Fortran

In C you can easily initialize an array using the curly braces syntax, if I remember correctly:
int* a = new int[] { 1, 2, 3, 4 };
How can you do the same in Fortran for two-dimensional arrays when you wish to initialize a matrix with specific test values for mathematical purposes? (Without having to doubly index every element on separate statements)
The array is either defined by
real, dimension(3, 3) :: a
or
real, dimension(:), allocatable :: a
You can do that using reshape and shape intrinsics. Something like:
INTEGER, DIMENSION(3, 3) :: array
array = reshape((/ 1, 2, 3, 4, 5, 6, 7, 8, 9 /), shape(array))
But remember the column-major order. The array will be
1 4 7
2 5 8
3 6 9
after reshaping.
So to get:
1 2 3
4 5 6
7 8 9
you also need transpose intrinsic:
array = transpose(reshape((/ 1, 2, 3, 4, 5, 6, 7, 8, 9 /), shape(array)))
For more general example (allocatable 2D array with different dimensions), one needs size intrinsic:
PROGRAM main
IMPLICIT NONE
INTEGER, DIMENSION(:, :), ALLOCATABLE :: array
ALLOCATE (array(2, 3))
array = transpose(reshape((/ 1, 2, 3, 4, 5, 6 /), &
(/ size(array, 2), size(array, 1) /)))
DEALLOCATE (array)
END PROGRAM main
For multidimensional (rank>1) arrays, the Fortran way for initialization differs from the C solution because in C multidimensional arrays are just arrays of arrays of etc.
In Fortran, each rank corresponds to a different attribute of the modified data type. But there is only one array constructor, for rank-1 arrays. From these two reasons, initialization through array constructor requires the RESHAPE intrisic function.
In addition to what has already been answered, there is a more direct way of entering the value of a matrix by row instead as by column: reshape has an optional argument ORDER which can be used to modify the order of filling the element of the multidimensional array with the entries of the array constructor.
For instance, in the case of the example in the first answer, one could write:
INTEGER, DIMENSION(3, 3) :: array=reshape( (/ 1, 2, 3, &
4, 5, 6, &
7, 8, 9 /), &
shape(array), order=(/2,1/) )
obtaining the filling of the matrix array exactly in the order shown by the lines of code.
The array (/2, 1/) forces the column index (2) to have precedence on the row index (1), giving the desired effect.
Array initialization can be done in the array declaration statement itself, as shown below:
program test
real:: x(3) = (/1,2,3/)
real:: y(3,3) = reshape((/1,2,3,4,5,6,7,8,9/), (/3,3/))
integer:: i(3,2,2) = reshape((/1,2,3,4,5,6,7,8,9,10,11,12/), (/3,2,2/))
end program test
It surprises me that
real:: y(3,3) = (/(/1,2,3/),(/4,5,6/),(/7,8,9/)/)
is not accepted by the compiler (tried g95, gfortran). It turns out that the shape of
(/(/1,2,3/),(/4,5,6/),(/7,8,9/)/) is 9 and not 3 3!

Resources