# Fortranで関数の出力として事前に知られていない配列を取得する方法

Python

```def select(x):
y = []
for e in x:
if e!=0:
y.append(e)
return y
```

それは次のように動作します：

```x = [1,0,2,0,0,3]
select(x)
[1,2,3]
```

Fortran に翻訳されます：

```function select(x,n) result(y)
implicit none
integer:: x(n),n,i,j,y(?)
j = 0
do i=1,n
if (x(i)/=0) then
j = j+1
y(j) = x(i)
endif
enddo
end function
```

1- y（？）を宣言する方法
2- 定義済みの値を宣言する方法
3 ディメンション情報を避ける方法

y（n）として定義されている場合は1になり、出力は次のようになります。

```x = (/1,0,2,0,0,3/)
print *,select(x,6)
1,2,3,0,0,0
```

which is not desired!
!-------------------------------
1- All given answers are useful in this post. Specially M.S.B and eryksun's.
2- I tried to adapt the ideas for my problem and compile with `F2Py` however it was not successful. I had already debugged them using GFortran and all were successful. It might be a bug in `F2Py` or something that I don't know about using it properly. I will try to cover this issue in another post.

Update: A linked question could be found at here.

15

どのようにして、PythonからFortranへのバック・ポーティングの位置づけになったのでしょうか？ o_Oこれはかなり珍しいようです。あるいは、Fortranを学問的な練習として学んでいますか？

## 3 答え

``````program test
implicit none
integer:: x(10) = (/1,0,2,0,3,0,4,0,5,0/)
print "(10I2.1)", select(x)

contains

function select(x) result(y)
implicit none
integer, intent(in):: x(:)
integer:: i, j, temp(size(x))
integer, allocatable:: y(:)

j = 0
do i = 1, size(x)
if (x(i) /= 0) then
j = j + 1
temp(j) = x(i)
endif
enddo

allocate(y(j))
y = temp(:j)
end function select

end program test
``````

M.S.B.の答えに基づいて、ここでは過剰割り当てで temp ` y `を増やす関数の改訂版があります。 前と同じように、最後に結果をyにコピーします。最終的に新しい配列を明示的に割り当てる必要はありません。代りに代入で自動的に行うことができます。

``````    function select(x) result(y)
implicit none
integer, intent(in):: x(:)
integer:: i, j, dsize
integer, allocatable:: temp(:), y(:)

dsize = 0; allocate(y(0))

j = 0
do i = 1, size(x)
if (x(i) /= 0) then
j = j + 1

if (j >= dsize) then         !grow y using temp
dsize = j + j/8 + 8
allocate(temp(dsize))
temp(:size(y)) = y
call move_alloc(temp, y) !temp gets deallocated
endif

y(j) = x(i)
endif
enddo
y = y(:j)
end function select
``````
13

コミュニティと知識を共有してくれてありがとう。あなたの答えとM.S.Bはお互いに非常に接近していて、とても役に立ちました。ちなみに、部分的に` j + j/8 + 8 `は整数のサイズのため、他のタイプのデータの変更が必要です。

@サポーター：たぶんそれは明らかではなかった。私はM.S.B.の代替回答の代わりにこのアップデートを追加しました。 1つ1つ、私は過剰なコピーが含まれていると思う配列を成長させる代わりに、私はそれを割り当てすぎた。必要な現在のサイズはj個のアイテムなので、私はそれに8分の1を割り振ります（小さい時には定数8を加えます）。したがって、過剰割り当てのサイズは、アレイの現在のサイズに比例して大きくなり、再割り当てが必要な回数が最小限に抑えられます。最後に私はそれを元に戻します。これは、コンパイラがコピーを必要としないように最適化されていることをうまく覚えています。

``````module my_subs

contains

function select(x) result(y)
implicit none
integer, dimension (:), intent (in) :: x
integer, dimension (:), allocatable :: y
integer :: i, j

j = 0
do i=1, size (x)
if (x(i)/=0) j = j+1
enddo

allocate ( y (1:j) )

j = 0
do i=1, size (x)
if (x(i)/=0) then
j = j+1
y(j) = x(i)
endif
enddo

return

end function select

end module my_subs

program test

use my_subs

implicit none
integer, dimension (6) :: array = [ 5, 0, 3, 0, 6, 1 ]
integer, dimension (:), allocatable :: answer

write (*, *) size (array), size (answer)
write (*, *) array

stop

end program test
``````

``````function select(x) result(y)
implicit none
integer, dimension (:), intent (in) :: x
integer, dimension (:), allocatable :: y, temp
integer :: i, j

j = 0
do i=1, size (x)
if (x(i)/=0) then
j = j+1
allocate (temp (1:j))
if ( allocated (y) ) temp (1:j-1) = y
call move_alloc (temp, y)
y(j) = x(i)
endif
enddo

return

end function select
``````
12

ご回答有難うございます。しかし、` eryksun `の答えに非常に近いものでした。この投稿は、Fortran 2003のいくつかの改善点を理解するのに役立ちました。

2回のフルパスを行うことも別の方法です。私は一時的な配列を選択しました。これは、関数で行われた作業（これは一般的ではありませんが）はおそらく結果をコピーするよりもコストがかかると考えています。また、Fortran 90/95の機能を割り当てる配列ではありませんか？

あなたの質問の例が本当にやりたいことであれば、Fortran90の組み込み `pack 'を使うことができます：

``````program pack_example

implicit none

integer, dimension(6) :: x

x = (/ 1,0,2,0,0,3 /)

! you can also use other masks than 'x/=0'
write(*,*) pack(x, x/=0)

end program pack_example
``````

サンプルプログラムの出力は次のとおりです。1 2 3

4

ヒントをありがとう。しかし問題の例は、問題の実証のためであった。とにかく、あなたのヒントは、あなたが提供した他のシンプルな状況に非常に便利です。実際には、与えられたサイズ情報なしのxに基づいて、例えば 'x/= 0'という条件に応じて、さまざまなサイズの配列を出力として返す方法を` pack `もう一つのポイントは、 'pack'出力は入力 'x'のサブセットであり、サイズを大きくすることはできません。結局それは良いヒントです。