我正在尝试实现一个python类型的df = df.groupby(['name','objective']).min()
运算符,该运算符检查一维数组是否包含某个元素。原则上,我可以使用它,但是我无法覆盖我要使用的两种类型的数组,即固定大小的数组和可分配的数组。下面的代码几乎可以满足我的要求:
in
按原样,代码将产生以下输出:
MODULE operator_in
IMPLICIT NONE
INTERFACE OPERATOR(.IN.)
MODULE PROCEDURE in_integer_list
! MODULE PROCEDURE in_integer_list_alloc
END INTERFACE OPERATOR(.IN.)
CONTAINS
FUNCTION in_integer_list(key, list) RESULT(res)
IMPLICIT NONE
INTEGER, INTENT(IN) :: key
INTEGER, INTENT(IN) :: list(:)
LOGICAL :: res
INTEGER :: ii
res = .FALSE.
DO ii = 1,SIZE(list)
IF (key == list(ii)) THEN
res = .TRUE.
RETURN
END IF
END DO
END FUNCTION in_integer_list
FUNCTION in_integer_list_alloc(key, list) RESULT(res)
IMPLICIT NONE
INTEGER, INTENT(IN) :: key
INTEGER, ALLOCATABLE, INTENT(IN) :: list(:)
LOGICAL :: res
IF (ALLOCATED(list)) THEN
res = in_integer_list(key, list)
ELSE
res = .FALSE.
END IF
END FUNCTION in_integer_list_alloc
END MODULE operator_in
PROGRAM test
USE operator_in
INTEGER :: list1(5) = (/1, 4, 6, 3, 8/)
INTEGER, ALLOCATABLE :: list2(:), list3(:)
INTEGER :: ii
ALLOCATE(list2(7))
list2(:) = (/8,7,6,5,4,2,1/)
DO ii = 1,5
IF (ii .IN. list1) THEN
WRITE (*,'(I3,A,5I3)') ii, ' is in ', list1
END IF
IF (ii .IN. list2) THEN
WRITE (*,'(I0.3,A,7I3)') ii, ' is in ', list2
END IF
! IF (ii .IN. list3) THEN
! WRITE (*,'(I3,A,7I3)') ii, ' is in ', list3
! END IF
END DO
END PROGRAM test
但是,如果我取消对最后三行的注释,
1 is in 1 4 6 3 8
1 is in 8 7 6 5 4 2 1
2 is in 8 7 6 5 4 2 1
3 is in 1 4 6 3 8
4 is in 1 4 6 3 8
4 is in 8 7 6 5 4 2 1
5 is in 8 7 6 5 4 2 1
由于未分配 IF (ii .IN. list3) THEN
WRITE (*,'(I0.3,A,7I3)') ii, ' is in ', list3
END IF
,代码因分段错误而崩溃:
list3
我试图通过编写第二个函数(Program received signal SIGSEGV: Segmentation fault - invalid memory reference.
Backtrace for this error:
#0 0x10925ebe4
#1 0x10925e306
#2 0x7fff5e878b5c
#3 0x1092547da
#4 0x109254bc5
#5 0x109254cce
Segmentation fault: 11
)来解决此问题,该函数允许可分配的数组,但是在我的界面中声明了两个函数:
in_integer_list_alloc
给我一个歧义错误:
INTERFACE OPERATOR(.IN.)
MODULE PROCEDURE in_integer_list
MODULE PROCEDURE in_integer_list_alloc
END INTERFACE OPERATOR(.IN.)
如果我在界面中注释掉了第一个过程:
FUNCTION in_integer_list(key, list) RESULT(res)
1
user-defined_operator.f90:27:2:
FUNCTION in_integer_list_alloc(key, list) RESULT(res)
2
Error: Ambiguous interfaces in operator interface 'in' for 'in_integer_list' at (1) and 'in_integer_list_alloc' at (2)
我当然遇到了固定大小的数组 INTERFACE OPERATOR(.IN.)
! MODULE PROCEDURE in_integer_list
MODULE PROCEDURE in_integer_list_alloc
END INTERFACE OPERATOR(.IN.)
的问题:
list1
所以:在代码由于未分配传递的数组而崩溃时,是否有一种聪明的方法来实现我想要的功能,或者至少获得正确的错误消息?
答案 0 :(得分:3)
理想情况下,重新设计代码,这样就无需处理未分配的数组。如果要表示一个空列表,请使用分配的零大小数组。
(未分配的对象在概念上更适合“没有列表”,而不是“列表为空”。从概念上讲,您不应该查询不存在的对象。)
如果必须的话,可以按照以下内容编写单个参数适配器函数:
FUNCTION foo(arg)
INTEGER, INTENT(IN), OPTIONAL:: arg(:)
INTEGER, ALLOCATABLE :: foo(:)
IF (PRESENT(arg)) THEN
foo = arg
ELSE
foo = [INTEGER ::]
END IF
END FUNCTION foo
然后可以使用适配器:
IF (item .in. foo(list)) THEN
...
适配器功能的适当命名留给阅读器。
(为适配器编写的虚拟参数为OPTIONAL,以容纳不存在的实际参数,未分配的实际参数和分离的实际参数。这是Fortran 2008的功能。)
答案 1 :(得分:1)
作为Python用户,我也很感激.in.
运算符可以提供的语法糖。也就是说,标准的Fortran也非常简洁:
if (any(items==value)) then
...
endif
但是,这是一种实现.in.
的方法,该方法应处理固定大小和可分配数组:
module operator_in
implicit none
interface operator(.in.)
module procedure operatorin
end interface operator(.in.)
contains
logical function operatorin(v,lst) result(found)
implicit none
integer, intent(in) :: v
integer, intent(in) :: lst(:)
integer, allocatable :: temp(:)
found = .false.
allocate(temp,source=lst)
if (size(temp)>0) then
if (any(temp == v)) found=.true.
endif
end function operatorin
end module operator_in
注意:我使用可分配的temp
数组,因此,如果使用check:all
(或类似版本)编译,则代码将运行而不会出现错误消息。另外,我使用any
来避免手动遍历项目列表。试试吧,很好。