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
这不是我想要的。会有什么问题?
我不确定您在 fListU
和 fListD
中的阅读情况如何。您需要意识到的一件事是,在 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
。
我有两个数组 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
这不是我想要的。会有什么问题?
我不确定您在 fListU
和 fListD
中的阅读情况如何。您需要意识到的一件事是,在 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
。