user27430
user27430

Reputation: 21

Array manipulation in Fortran

I have two arrays fListU and fListD both of which contain 4-tuples. Specifically:

fListU = [(2, 1, 1, 0), (2, 5, 5, 0), (5, 4, 10, 0), (6, 1, 5, 0), (6, 5, 7, 0)]
fListD = [(1, 4, 0, 4), (3, 4, 0, 4), (5, 4, 0, 6)]

Now I want to put together these into one array, with the condition that when the first two items of the tuples are equal, then the third and fourth items of two lists should be added. In this case, the result I am looking for is

fList = [(2, 1, 1, 0), (2, 5, 5, 0), (5, 4, 10, 6), (6, 1, 5, 0), 
         (6, 5, 7, 0), (1, 4, 0, 4), (3, 4, 0, 4)]

where (5, 4, 10, 0) and (5, 4, 0, 6) are combined to (5, 4, 10, 6).

This is what I tried.

ALLOCATE (fList((n-1)**2,4))
fList = 0
p = 1   ! p signifies the position in fList.
DO k = 1, ((n-1)**2), 1 ! k is the index for fListD
  DO l = 1, ((n-1)**2), 1 ! l is the index for fListU
    IF ( ALL (fListU(l,1:2) == fListD(k,1:2)) ) THEN
      fList(p,1:2) = fListU(l,1:2)
      fList(p,3) = fListU(l,3)
      fList(p,4) = fListD(k,4)
    ELSE
      fList(p,:) = fListU(l,:)
      p = p+1
      fList(p,:) = fListD(k,:)
      p = p+1
    END IF
  END DO
END DO

This is not producing what I want. What would be the problem?

Upvotes: 0

Views: 1150

Answers (1)

chw21
chw21

Reputation: 8140

I'm not sure how you are reading in fListU and fListD. One thing that you need to realise is that in Fortran (other than most other programming languages), the first index of a multi-dimensional array is the fastest changing. That's why the way you read the data in is so important: If you read the data in sequentially, or use reshape, then the second element you read in will be in position (2, 1), not (1, 2) as you might expect.

So I strongly suggest to have the shape of fListU as (4, 5), not (5, 4), and consequently address the first two elements of a tuple as flist(1:2, p).

Here's a possible solution that knows the lengths of the two input arrays. The output will still contain another line of all zeros, because I haven't programmed it to get the size of the output array right (instead it just uses the sum of the sizes of the input arrays).

program Combine_List_Simple
    implicit none
    integer, dimension(:, :), allocatable :: fListU, fListD, fList
    integer :: u_size, d_size
    integer :: u_index, d_index, f_index

    u_size = 5
    allocate(fListU(4, u_size))
    fListU = reshape((/2, 1, 1, 0, 2, 5, 5, 0, 5, 4, 10, 0, &
                       6, 1, 5, 0, 6, 5, 7, 0/), (/4, u_size/))

    d_size = 3
    allocate(fListD(4, d_size))
    fListD = reshape((/1, 4, 0, 4, 3, 4, 0, 4, 5, 4, 0, 6/), &
                     (/4, d_size/))

    allocate(fList(4, u_size + d_size))
    flist(:, 1:u_size) = fListU(:, :)
    flist(:, u_size+1:) = 0
    f_index = u_size+1
    d_loop : do d_index = 1, d_size
      do u_index = 1, u_size
        if (all(fListD(1:2, d_index) == fList(1:2, u_index))) then
          fList(4, u_index) = fListD(4, d_index)
          cycle d_loop
        end if
      end do
      fList(:, f_index) = fListD(:, d_index)
      f_index = f_index+1
    end do d_loop

    write(*, '(4I4)') fList

end program Combine_List_Simple

This code also assumes that the 4th element of all tuples in fListU and the 3rd element of all tuples in fListD is zero. But your code seems to assume that as well. Also it assumes that the combination of 1st and 2nd elements of the tuples are unique in each of the input arrays.

First, I completely copy the contents of fListU into fList. Then I loop over fListD, and compare it to the first entries in fList, because that's where the contents of fListU are. If it finds a match, it updates only the 4th element of the tuple, and then cycles the loop of the fListD array.

Only if it doesn't find a match will it reach the end of the inner loop, and then append the tuple to fList.

Upvotes: 1

Related Questions