Fortran 中的数组操作

Array manipulation in Fortran

我有两个数组 fListU 和 fListD,它们都包含 4 元组。具体来说:

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)]

现在我想将它们放在一个数组中,条件是当元组的前两项相等时,应添加两个列表的第三项和第四项。在这种情况下,我要查找的结果是

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)]

其中 (5, 4, 10, 0) 和 (5, 4, 0, 6) 合并为 (5, 4, 10, 6)。

这是我试过的。

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

这不是我想要的。会有什么问题?

我不确定您在 fListUfListD 中的阅读情况如何。您需要意识到的一件事是,在 Fortran 中(与大多数其他编程语言不同),多维数组的 first 索引是 变化最快的 。这就是读取数据的方式如此重要的原因:如果您按顺序读取数据,或者使用 reshape,那么您读取的第二个元素将位于 (2, 1) 位置,而不是 [=15] =] 如您所料。

所以我强烈建议 fListU 的形状为 (4, 5),而不是 (5, 4),因此将元组的前两个元素表示为 flist(1:2, p)

这是一个可能的解决方案,它知道两个输入数组的长度。 输出仍将包含另一行全零,因为我没有对其进行编程以正确获取输出数组的大小(相反,它仅使用输入数组大小的总和)。

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

此代码还假定 fListU 中所有元组的第 4 个元素和 fListD 中所有元组的第 3 个元素为零。但是您的代码似乎也假设了这一点。它还假定元组的第一个和第二个元素的组合在每个输入数组中都是唯一的。

首先,我将fListU的内容完整复制到fList中。然后我遍历 fListD,并将它与 fList 中的第一个条目进行比较,因为那是 fListU 的内容所在的位置。如果找到匹配项,它只更新元组的第 4 个元素,然后循环 fListD 数组的循环。

只有没有找到匹配才会到达内循环的末尾,然后将元组追加到fList