英文:
Re-organising the data with desired sequence
问题
我修改了我的发布的问题。
以下是我的Fortran代码。
1 PROGRAM COMPA
2 IMPLICIT NONE
3
4 INTEGER, PARAMETER :: dp = SELECTED_REAL_KIND(15,14)
5 INTEGER :: i, j, k, l
6 REAL (KIND=dp) :: ap(116,6), lr(3,3), pl(3), ns(2,116)
7
8 OPEN (UNIT=3, FILE='data.dat', STATUS='OLD')
9 READ (UNIT=3, FMT=*)
10 READ (UNIT=3, FMT=*)
11 DO i = 1, 3, 1
12 READ (UNIT=3, FMT=*) pl
13 lr(i,:) = pl
14 END DO
15 READ (UNIT=3, FMT=*)
16 DO i = 1, 116, 1
17 READ (UNIT=3, FMT=*) pl
18 ap(i,4:6) = pl
19 ns(:,i) = i
20 END DO
21
22 DO i = 1, 116, 1
23 ap(i,1) = ap(i,4)*lr(1,1)+ap(i,5)*lr(2,1)+ap(i,6)*lr(3,1)
24 ap(i,2) = ap(i,4)*lr(1,2)+ap(i,5)*lr(2,2)+ap(i,6)*lr(3,2)
25 ap(i,3) = ap(i,4)*lr(1,3)+ap(i,5)*lr(2,3)+ap(i,6)*lr(3,3)
26 END DO
27
28 DO i = 2, 116, 1
29 l = i
30 DO j = 1, i-1, 1
31 IF ((ap(l,1) < ap(j,1)) .OR. &
32 ((ap(l,1) == ap(j,1)) .AND. (ap(l,2) < ap(j,2))) .OR. &
33 ((ap(l,1) < ap(j,1)) .AND. (ap(l,2) == ap(j,2)) .AND. &
34 (ap(l,3) < ap(j,3)))) THEN
35 k = ns(1,i)
36 ns(1,j+1:i) = ns(1,j:i-1)
37 ns(1,j) = k
38 l = j
39 END IF
40 END DO
41 END DO
42
43 OPEN (UNIT=4, FILE='compare.dat', STATUS='UNKNOWN')
44 DO i = 1, 116, 1
45 DO j = 1, 116, 1
46 IF (ns(1,j) == i) WRITE (UNIT=4, FMT=*) ns(:,j), ap(j,1:3)
47 END DO
48 END DO
49
50 CLOSE (UNIT=3)
51 CLOSE (UNIT=4)
52 STOP
53 END PROGRAM COMPA
我的代码读取以下data.dat文件内容,ap(i,4:6)存储来自文件的原始数据;而ap(i,1:3)存储处理后的数据ap(i,4:6)。
我想要重新组织每行的行号,基于每行中第一个值的升序顺序。如果两个或更多行的第一个值相同,则根据第二个值进行升序重新排列。如果两个或更多行的第二个值相同,则根据第三个值进行升序重新排列。
以下是data.dat文件的内容。
116
Parameter
0.2951429939E+02 0.0000000000E+00 0.0000000000E+00
0.0000000000E+00 0.1500000000E+02 0.0000000000E+00
0.0000000000E+00 0.0000000000E+00 0.2510000038E+02
Parameter
0.000000000 0.500000000 0.300000012
0.041669998 0.500000000 0.328289986
0.041669998 0.500000000 0.384860009
0.000000000 0.500000000 0.413150012
0.000000000 0.500000000 0.469720006
0.041669998 0.500000000 0.498010010
0.041669998 0.500000000 0.554579973
0.000000000 0.500000000 0.582870007
0.083329998 0.500000000 0.300000012
0.125000000 0.500000000 0.328289986
0.125000000 0.500000000 0.384860009
0.083329998 0.500000000 0.413150012
0.083329998 0.500000000 0.469720006
...
以下是由代码写入的re-organised数据的compare.dat文件。
1.0000000000000000 1.0000000000000000 0.0000000000000000 7.5000000000000000 7.5300004152000044
2.0000000000000000 7.0000000000000000 1.2298607965527013 7.5000000000000000 13.919957533040389
3.0000000000000000 8.0000000000000000 0.0000000000000000 7.5000000000000000 14.630037397190
<details>
<summary>英文:</summary>
I revise my posted question.
Here is my Fortran code.
line 1 PROGRAM COMPA
line 2 IMPLICIT NONE
line 3
line 4 INTEGER, PARAMETER :: dp = SELECTED_REAL_KIND(15,14)
line 5 INTEGER :: i, j, k, l
line 6 REAL (KIND=dp) :: ap(116,6), lr(3,3), pl(3), ns(2,116)
line 7
line 8 OPEN (UNIT=3, FILE='data.dat', STATUS='OLD')
line 9 READ (UNIT=3, FMT=)
line 10 READ (UNIT=3, FMT=)
line 11 DO i = 1, 3, 1
line 12 READ (UNIT=3, FMT=) pl
line 13 lr(i,:) = pl
line 14 END DO
line 15 READ (UNIT=3, FMT=)
line 16 DO i = 1, 116, 1
line 17 READ (UNIT=3, FMT=*) pl
line 18 ap(i,4:6) = pl
line 19 ns(:,i) = i
line 20 END DO
line 21
line 22 DO i = 1, 116, 1
line 23 ap(i,1) = ap(i,4)*lr(1,1)+ap(i,5)*lr(2,1)+ap(i,6)*lr(3,1)
line 24 ap(i,2) = ap(i,4)*lr(1,2)+ap(i,5)*lr(2,2)+ap(i,6)*lr(3,2)
line 25 ap(i,3) = ap(i,4)*lr(1,3)+ap(i,5)*lr(2,3)+ap(i,6)lr(3,3)
line 26 END DO
line 27
line 28 DO i = 2, 116, 1
line 29 l = i
line 30 DO j = 1, i-1, 1
line 31 IF ((ap(l,1) < ap(j,1)) .OR. &
line 32 ((ap(l,1) == ap(j,1)) .AND. (ap(l,2) < ap(j,2))) .OR. &
line 33 ((ap(l,1) < ap(j,1)) .AND. (ap(l,2) == ap(j,2)) .AND. &
line 34 (ap(l,3) < ap(j,3)))) THEN
line 35 k = ns(1,i)
line 36 ns(1,j+1:i) = ns(1,j:i-1)
line 37 ns(1,j) = k
line 38 l = j
line 39 END IF
line 40 END DO
line 41 END DO
line 42
line 43 OPEN (UNIT=4, FILE='compare.dat', STATUS='UNKNOWN')
line 44 DO i = 1, 116, 1
line 45 DO j = 1, 116, 1
line 46 IF (ns(1,j) == i) WRITE (UNIT=4, FMT=) ns(:,j), ap(j,1:3)
line 47 END DO
line 48 END DO
line 49
line 50 CLOSE (UNIT=3)
line 51 CLOSE (UNIT=4)
line 52 STOP
line 53 END PROGRAM COMPA
My code reads the following data.dat file content. and ap(i,4:6) stores the original data from the file; while, ap(i,1:3) stores the data after processing ap(i,4:6).
I want to re-organise the line number for each row, based on the ascending sequence for the 1st value in each row. If the 1st value is same in two or more rows; then, take the 2nd value for the ascending re-organising sequence. If the 2nd value is same in two or more rows; then, take the 3rd value for the ascending re-organising sequence.
Here is the data.dat file.
116
Parameter
0.2951429939E+02 0.0000000000E+00 0.0000000000E+00
0.0000000000E+00 0.1500000000E+02 0.0000000000E+00
0.0000000000E+00 0.0000000000E+00 0.2510000038E+02
Parameter
0.000000000 0.500000000 0.300000012
0.041669998 0.500000000 0.328289986
0.041669998 0.500000000 0.384860009
0.000000000 0.500000000 0.413150012
0.000000000 0.500000000 0.469720006
0.041669998 0.500000000 0.498010010
0.041669998 0.500000000 0.554579973
0.000000000 0.500000000 0.582870007
0.083329998 0.500000000 0.300000012
0.125000000 0.500000000 0.328289986
0.125000000 0.500000000 0.384860009
0.083329998 0.500000000 0.413150012
0.083329998 0.500000000 0.469720006
...
Here is the compare.dat file, which was written by the code for the re-organised data.
1.0000000000000000 1.0000000000000000 0.0000000000000000 7.5000000000000000 7.5300004152000044
2.0000000000000000 7.0000000000000000 1.2298607965527013 7.5000000000000000 13.919957533040389
3.0000000000000000 8.0000000000000000 0.0000000000000000 7.5000000000000000 14.630037397190604
4.0000000000000000 6.0000000000000000 1.2298607965527013 7.5000000000000000 12.500051440243805
5.0000000000000000 5.0000000000000000 0.0000000000000000 7.5000000000000000 11.789972329093603
6.0000000000000000 13.000000000000000 2.4594265091401013 7.5000000000000000 11.789972329093603
7.0000000000000000 16.000000000000000 2.4594265091401013 7.5000000000000000 14.630037397190604
8.0000000000000000 4.0000000000000000 0.0000000000000000 7.5000000000000000 10.370065458197006
9.0000000000000000 21.000000000000000 4.9191481317598029 7.5000000000000000 11.789972329093603
10.000000000000000 102.00000000000000 15.042847316209118 7.5000000000000000 14.464879495090205
11.000000000000000 114.00000000000000 13.527288986990197 7.5000000000000000 13.589893105343398
12.000000000000000 91.000000000000000 0.0000000000000000 7.5000000000000000 6.4399073735966041
13.000000000000000 69.000000000000000 23.365586106424487 7.5000000000000000 9.6599863721468040
14.000000000000000 83.000000000000000 27.054873530174486 7.5000000000000000 7.5300004152000044
15.000000000000000 84.000000000000000 28.284437826075518 7.5000000000000000 8.2400787733501950
16.000000000000000 24.000000000000000 4.9191481317598029 7.5000000000000000 14.630037397190604
17.000000000000000 104.00000000000000 17.216575554825518 7.5000000000000000 15.719879815290209
18.000000000000000 89.000000000000000 28.284437826075518 7.5000000000000000 13.919957533040389
19.000000000000000 64.000000000000000 20.905862978575517 7.5000000000000000 12.500051440243805
20.000000000000000 36.000000000000000 9.8380015632401978 7.5000000000000000 10.370065458197006
21.000000000000000 80.000000000000000 25.825011966250003 7.5000000000000000 12.500051440243805
Obviously, this re-organisation is wrong because the row was not written based on the ascending order.
Would anyone please give me some suggestions on what is wrong with my code? Thank you very much.
</details>
# 答案1
**得分**: 1
首先,为了提高代码清晰度,让我们定义一个实用函数,用于判断一行是否与另一行相比较“较小”(因为它使用了假定的形状参数,这个函数必须位于一个模块中,或者位于主程序的`contain`部分):
```fortran
logical function is_smaller(rowa, rowb) result(s)
real(dp), intent(in) :: rowa(:), rowb(:)
s = .false.
if (rowa(1) < rowb(1)) then
s = .true.
else if (rowa(1) == rowb(1)) then
if (rowa(2) < rowb(2)) then
s = .true.
else if (rowa(2) == rowb(2)) then
if (rowa(3) < rowb(3)) s = .true.
end if
end if
end function
然后,让我们将它与插入排序算法一起使用,对于这么多要排序的元素,插入排序算法是可以的。再次为了代码清晰度,我们移动数据而不是使用索引(使用索引可能更有效)。
real(dp) :: tmp(6)
...
do i = 2, 116
! 前面的(i-1)行已经排序,现在我们处理第i行
do j = 1, i-1
if (is_smaller(ap(i,:), ap(j,:))) then
! 在位置j插入第i行
tmp(:) = ap(i,:)
ap(j+1:i,:) = ap(j:i-1,:)
ap(j,:) = tmp(:)
exit
end if
end do
end do
这是您所提供代码的翻译部分。
英文:
First for code clarity let's define a utility function tells if a row is "smaller" or not compared to another row (because it uses assumed shape arguments, this function must be in a module, or in the contain
section of the main program):
logical function is_smaller(rowa,rowb) result(s)
real(dp), intent(in) :: rowa(:), rowb(:)
s = .false.
if (rowa(1) < rowb(1)) then
s = .true.
else if (rowa(1) == rowb(1)) then
if (rowa(2) < rowb(2)) then
s = .true.
else if (rowa(2) == rowb(2)) then
if (rowa(3) < rowb(3)) s= .true.
end if
end if
end function
Then let's use it with an insertion sort algorithm, which is is fine for such a number of elements to sort. For code clarity again we move the data instead of using indexes (indexes would be more efficient).
real(dp) :: tmp(6)
...
do i = 2, 116
! the first (i-1) rows are sorted, we are now looking at row i
do j = 1, i-1
if (is_smaller(ap(i,:),ap(j,:))) then
! insertion of row i at position j
tmp(:) = ap(i,:)
ap(j+1:i,:) = ap(j:i-1,:)
ap(j,:) = tmp(:)
exit
end if
end do
end do
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论