Excel VBA質問箱 IV

当質問箱は、有志のボランティア精神のおかげで成り立っています。
問題が解決したら、必ずお礼をしましょうね。
本サイトの基本方針をまとめました。こちら をご一読ください。

投稿種別の選択が必要です。ご注意ください。
迷惑投稿防止のため、URLの入力を制限しています。ご了承ください。


272 / 13645 ツリー ←次へ | 前へ→

【81237】配列を戻り値とする関数 akiholic 20/3/25(水) 23:05 質問[未読]
【81238】Re:配列を戻り値とする関数 γ 20/3/26(木) 16:53 発言[未読]
【81240】Re:配列を戻り値とする関数 akiholic 20/3/29(日) 13:11 お礼[未読]
【81239】Re:配列を戻り値とする関数 Jaka 20/3/27(金) 20:54 発言[未読]
【81241】Re:配列を戻り値とする関数 akiholic 20/3/29(日) 13:25 お礼[未読]
【81242】Re:配列を戻り値とする関数 Jaka 20/3/31(火) 3:04 発言[未読]
【81243】Re:配列を戻り値とする関数 akiholic 20/3/31(火) 23:24 回答[未読]

【81237】配列を戻り値とする関数
質問  akiholic  - 20/3/25(水) 23:05 -

引用なし
パスワード
   配列を戻り値とする関数として、以下のようなコードを考えています。
TestFunc1のように、戻り値用の変数(ret)を使って記載すれば問題ないですが、
TestFunc2のように、直接戻り値(TestFunc2)を使って記載するとエラーになります。
どうもTestFunc2(0)が、関数呼び出しとして解釈されているようですが、
この問題を回避する方法をご存じの方がいらっしゃればご教示いただきたく。
なお、大規模な配列を想定しており、戻り値用のテンポラリ変数を使用してしまうと、
要素がコピーされることを回避したいと考えたことが発端です。

Sub Test()
  Dim a As Variant, b As Variant
  a = Array(1)
  b = TestFunc1(a)
  Debug.Print b(0)

  b = TestFunc2(a)
  Debug.Print b(0)
End Sub

Function TestFunc1(a As Variant) As Variant
  Dim ret As Variant
  ret = a
  ret(0) = 10
  TestFunc1 = ret
End Function

Function TestFunc2(a As Variant) As Variant
  TestFunc2 = a
  TestFunc2(0) = 10
End Function

【81238】Re:配列を戻り値とする関数
発言  γ  - 20/3/26(木) 16:53 -

引用なし
パスワード
   最初の方式も、プロシージャを抜けると
ローカル変数retは解放されるので負担にはならないのでは?
どうしてもというなら、
aを参照渡しを使って修正すればいいのでは?

【81239】Re:配列を戻り値とする関数
発言  Jaka  - 20/3/27(金) 20:54 -

引用なし
パスワード
   こうすれば良いんじゃないの?

Function TestFunc2(a As Variant) As Variant
  a(0) = 10
  TestFunc2 = a
End Function

【81240】Re:配列を戻り値とする関数
お礼  akiholic  - 20/3/29(日) 13:11 -

引用なし
パスワード
   レスありがとうございます。

サンプル程度の内容であれば、retのコピー負荷は気になりませんが、配列のサイズが大きくなり、実行回数が増えて来るとret確保分の処理負荷が無視できなくなってきたので、質問させて頂きました。
文法の記法でTestFunc2のような書き方ができればと思ったのですが、やはり参照渡しでやることにしようと思います。

【81241】Re:配列を戻り値とする関数
お礼  akiholic  - 20/3/29(日) 13:25 -

引用なし
パスワード
   レスありがとうございます。

引数で渡した配列は、破壊したくないので、一度はコピーが必要と考えています。
文法上の記法を私が知らないだけで、TestFunc2と同等の内容が表現できればと思ったのですが。。。

vbaでTestFunc2を表現できないのであれば、戻り値を参照渡しとして対応することを考えたいと思っています。

【81242】Re:配列を戻り値とする関数
発言  Jaka  - 20/3/31(火) 3:04 -

引用なし
パスワード
   ▼akiholic さん:
>引数で渡した配列は、破壊したくないので、一度はコピーが必要と考えています。
>文法上の記法を私が知らないだけで、TestFunc2と同等の内容が表現できればと思ったのですが。。。
>
>vbaでTestFunc2を表現できないのであれば、戻り値を参照渡しとして対応することを考えたいと思っています。

破壊したくないの意味が良く解ってないけど、
ByValにすれば・・・?。

Sub Test()
  Dim a As Variant, b As Variant
  a = Array(1)
'  b = TestFunc1(a)
'  Debug.Print b(0)

  b = TestFunc2(a)
  Debug.Print b(0)
  Debug.Print a(0)
End Sub

Function TestFunc2(ByVal a As Variant) As Variant
  a(0) = 10
  TestFunc2 = a
End Function

【81243】Re:配列を戻り値とする関数
回答  akiholic  - 20/3/31(火) 23:24 -

引用なし
パスワード
   ▼Jaka さん:
>▼akiholic さん:
>>引数で渡した配列は、破壊したくないので、一度はコピーが必要と考えています。
>>文法上の記法を私が知らないだけで、TestFunc2と同等の内容が表現できればと思ったのですが。。。
>>
>>vbaでTestFunc2を表現できないのであれば、戻り値を参照渡しとして対応することを考えたいと思っています。
>
>破壊したくないの意味が良く解ってないけど、
>ByValにすれば・・・?。
>
>Sub Test()
>  Dim a As Variant, b As Variant
>  a = Array(1)
>'  b = TestFunc1(a)
>'  Debug.Print b(0)
>
>  b = TestFunc2(a)
>  Debug.Print b(0)
>  Debug.Print a(0)
> End Sub
>
>Function TestFunc2(ByVal a As Variant) As Variant
>  a(0) = 10
>  TestFunc2 = a
> End Function

ByValで渡すと、その時点でコピーが生成されてしまうので、効率は悪いように思われます。
以下のコードで実験してみましたが、参照渡しの引数として結果を受け取るのが、効率としては良さそうですね。。。
気軽に動的配列を扱っていたのですが、代入させたり関数処理させた際に、やたらと処理が重くなることに気づいて、TestFunc3を考えたのですが、意図通りには動かなかったので、質問させて頂きました。

===
#If VBA7 Then
Declare PtrSafe Function timeGetTime Lib "winmm.dll" () As Long
#Else
Declare Function timeGetTime Lib "winmm.dll" () As Long
#End If

Sub Test()
  Dim a As Variant, b As Variant, c As Variant, d As Variant, e As Variant, f As Variant, i As Long, dmy As Variant, j As Long, T0 As Long
  ReDim a(100000) As Double
  For i = 0 To 100000
   a(i) = Rnd()
  Next i
 
  T0 = timeGetTime()
  For i = 0 To 1000
   b = TestFunc1(a)
  Next
  Debug.Print timeGetTime() - T0
 
  T0 = timeGetTime()
  For i = 0 To 1000
   c = TestFunc2(a)
  Next
  Debug.Print timeGetTime() - T0
 
  'T0 = timeGetTime()
  'For i = 0 To 1000
  '  d = TestFunc3(a)
  'Next
  'Debug.Print timeGetTime() - T0
 
  T0 = timeGetTime()
  For i = 0 To 1000
   Call TestFunc4(a, e)
  Next
  Debug.Print timeGetTime() - T0
 
  T0 = timeGetTime()
  For i = 0 To 1000
   f = a
   f(0) = 50
  Next
  Debug.Print timeGetTime() - T0
 
  Debug.Print a(0), b(0), c(0), e(0), f(0)
End Sub

Function TestFunc1(x As Variant) As Variant
  Dim y As Variant
  y = x
  y(0) = 10
  TestFunc1 = y
End Function

Function TestFunc2(ByVal x As Variant) As Variant
  x(0) = 20
  TestFunc2 = x
End Function

'Function TestFunc3(x As Variant) As Variant
'  TestFunc3 = x
'  TestFunc3(0) = 30 * Rnd()
'End Function

Function TestFunc4(x As Variant, y As Variant) As Variant
  y = x
  y(0) = 40
End Function

<<実行結果>>
TestFunc1: 112
TestFunc2: 97
TestFunc4: 47
ベタ: 47

272 / 13645 ツリー ←次へ | 前へ→
ページ:  ┃  記事番号:
2610219
(SS)C-BOARD v3.8 is Free