No.6ベストアンサー
- 回答日時:
こんばんは。
>ずうずうしい質問で申し訳ないのですが
次はないと思って、聞けるときに、聞いてください。
勉強のためだとしたら、本当に、良い教材かもしれません。VBAで必要な基礎は全部含まれていますし、結構、難しい内容です。
なお、#4のマクロコードに関しては、たぶん、半年とか1年では出来ません。ところが、私自身の経験ですが、ある日突然分かるようになるのですね。これを書いた人のは、こんなことを考えていたのかって、ずっと後に知ることになります。最初、さっぱり分からないものがあります。
>kei=kei+c.Valueとありますが
>.Valueがなぜ必要なのでしょうか
最初に、この件からです。実は、結論自体は、あまり書かれていないはずです。もちろん、.Value なしでも、合計値は変わりません。
標準のプロパティ
http://officetanaka.net/excel/vba/speed/s8.htm
#標準のプロパティであるValueプロパティを省略せずに書くと約20%も高速化します。
#今回あらためて検証を行った結果、高速化と言えるほどの差が出ないことがわかりました。
この書いた人は、有名なインストラクターですが、本来、この問題は、速さの違いではありません。
「プロパティなし」ですと、暗黙のプロパティから、.Value 値になりますが、デフォルト・プロパティを書くべきか、しなくてよいのか、という問題に対して、私は、「必ず入れる」というのを原則としています。曖昧にはしないほうがよいと思います。
「明示的(.Valueを入れる)」か「暗黙的(いれないで使う)」かということとは、私の経験則からですが、「プロパティなし=暗黙的」の場合、外部からオートメーション(OLE)として使うと、うまくいきません。理由はよく分かりませんが、おそらく、Office のVBEの中でしか、自動的に、暗黙のプロパティが取れないからだと思います。
そういう理屈は別にしても、Microsoft から出されるサンプルなどには、そうした暗黙のプロパティのまま、つまり「Cells(1,1)/Range("A1")」のままに書いているコードは、ないからなのです。
>If TypeName(v) = "Range" Then
>の部分がよくわかりません
これは、v という変数が、どういう種類のものかを分けて処理する必要があるからです。
TypeName(変数)とすると、どういう型なの、返ります。
セルを参照すると、"Range"となって、数字を入れれば、ワークシートからのものは、すべて、"Double"型になります。文字を入れれば、"String"が出てきます。
'実験
Function TYN(a As Variant)
TYN = TypeName(a)
End Function
話を元に戻すと、
For Each v In ar '←パラメータ配列(配列)
'v は、配列の中のひとつ
If TypeName(v) = "Range" Then
'Range型なら、通常のループで出来ます。
For Each c In v '←ここにセルの範囲が入れば、そのまま取れません。
kei = kei + c.Value
Next
Else
'単純な値なら、そのまま足し算すればよいです。
kei = kei + v
End If
Next v
つまり、パラメータ配列という、ひとつひとつの中身は、Range型のように二重の構造になっているものがあります。それは、そのまま、「kei + v」のようには計算できませんので、もう一度、ループしてあげる必要があります。
解りやすい解説ありがとうございます
この一連のやりとりは
この先何度も見直すとおもいます。
貴重な時間を割いていただいて本当にありがとうございました。
No.5
- 回答日時:
補足:
本当は、#1さん、#2さんのコードを組みあせるのでしたら、こんな感じです。最初は、なかなか、こういうことも思いつきません。
Function kei(ParamArray ar() As Variant) As Variant
Dim v As Variant
Dim c As Variant
For Each v In ar
If TypeName(v) = "Range" Then
For Each c In v
kei = kei + c.Value
Next
Else
kei = kei + v
End If
Next v
End Function
出力型は、本来は、Double型ですが、エラー値の出力はありませんが、今後のエラー値を予想して、Variant 型になります。
kei(ParamArray ar() As Variant) As Variant ←この部分。
ParamArray は、「パラメータ配列」と呼びます。バラメータ配列は、何でも入るので、Variant 型のみです。
ちなみに、変数の v は、Value の頭の1文字
ar は、Array の二文字。
c は、cell の意味です。
時々、自分で関数をVBAで作ってみると、とても勉強になります。特に、私が作って不思議さを感じるのは、RANK関数です。RANK関数は、初期の頃のままになっています。なぜ、もう少し便利に作らなかったのかなって思うことがあります。SUMIF などは比較的に簡単です。ただ、実際の内部の仕様は公開はされていませんので、試してみるまで分からないものもあります。INDEX 関数などは、変わっていて、戻り値が、値が返っているように見えますが、RANGE型が返っています。
この回答への補足
何度もありがとうございます
ずうずうしい質問で申し訳ないのですが
If TypeName(v) = "Range" Then
の部分がよくわかりません
またそのとき
kei=kei+c.Valueとありますが
.Valueがなぜ必要なのでしょうか
「vが複数範囲であるならそれぞれの数値に対して加算しなさい」
ということでしょうか?
No.4
- 回答日時:
#3です。
補足:
>SUM関数と全く同じものをVBAでつくるとどのような式(?)になるのでしょうか?
私は、読み落としていたけれども、「まったく同じもの」というのは、遥か先の話ですね。
少なくとも、「初心者」という銘を打っている限りは、難しいです。以下ですと、私が、何年か前に書いたもので、中級レベルの技術で書かれたものです。
例えば、このような計算が可能です。
A1~A9 まで、1,2,3,4,5,6,7,8,9 と入れておいて、
=MYSUM(A1:A9+1)
とし、配列の確定(F2を押して、『ShiftとCtrlを押しながらEnterキー』を押す)で、「54」という答えが出せます。中身は、2,3,4,5,6,7,8,9,10 と計算したものと同じです。
VBAのプログラミングの本質的なところは、初級も上級も変わらないのですが、エラー対策を施せるようになると技術的に上になっていきます。エラー対策など必要がないと思っている限りは、なかなか上に上がっていきません。
SUM関数と同じようなエラーが出で来るはずです。ただ、完全に、エラーを排出できるわけではありません。例えば、[循環参照ダイアログ]の呼び出しが出来ません。#VALUE! エラーになるだけです。
このコードは、最初に、関数を入れて、入れた状態で、Ctrl + A のショートカットで、SUMと同じように出てくるかどうか、というところから始まっています。それから、[チップ・テキスト(クリーム色のヘルプメッセージ)]は出てきません。
それと、少しVBAやExcelを詳しい人ですと、揮発性(Volatile)とか不揮発性とか言う人がいます。簡単に、Volatile メソッドを入れればよいと思っている人もいるようですが、それは、少し考え違いをしています。それは、実際、引数の変化によって、値が変わればよいのですから、必ずしも、Volatile メソッドは必要がないのです。
'------------------------------------------------------
Public Function MySum(数値1 As Variant, ParamArray 数値2() As Variant) As Variant
Dim dblTotal As Double
Dim ar As Variant
Dim c As Variant
Dim Arg As Variant
Dim Args() As Variant
Dim fml As String
Const vbMyError As Integer = 513
On Error Resume Next
fml = Application.Caller.FormulaR1C1
On Error GoTo ErrHandler
If InStr(fml, "RC") > 0 Then
Err.Raise vbMyError 'すべての循環参照は検出できない
ElseIf InStr(fml, "R") = 0 And InStr(fml, "C") = 0 Then
Err.Raise vbMyError + 1
End If
If TypeName(数値1) = "Range" Then
Set Arg = 数値1
For Each c In Arg
If VarType(c) = vbDouble Then
dblTotal = dblTotal + c.Value
End If
Next c
ElseIf TypeName(数値1) = "Double" Then
Arg = 数値1
dblTotal = dblTotal + Arg
ElseIf UBound(数値1, 1) > -1 Or UBound(数値1, 2) > -1 Then
Arg = 数値1
'配列時の計算
For Each c In Arg
dblTotal = dblTotal + c
Next c
MySum = dblTotal
End If
If Not IsMissing(数値2) Then
Args() = 数値2
ElseIf UBound(数値2) = -1 Then
'配列が確保されていない時の離脱条件
MySum = dblTotal
Exit Function
End If
For Each ar In Args()
If TypeName(ar) = "Range" Then
For Each c In ar
If VarType(c) = vbDouble Then
dblTotal = dblTotal + c.Value
End If
Next c
ElseIf TypeName(ar) = "Double" Then
dblTotal = dblTotal + ar
End If
Next ar
MySum = dblTotal
Exit Function
ErrHandler:
'エラー処理
If Err.Number = vbMyError Then
MySum = CVErr(xlErrValue)
ElseIf Err.Number = vbMyError + 1 Then
MySum = CVErr(xlErrName)
ElseIf IsError(数値1) Then
MySum = CVErr(数値1) '←この部分は検証されていない
End If
End Function
SUM関数、実は奥が深いんですね。全く知りませんでした。
お門違いもいいところですね、私。。
SUM関数に似たものを作ろうとしていたので、SUM関数の
中身をいじくってマクロを作成しようとしてました。
今回はマクロとセル中の式で強引に作って完成させました。
今後Wendy02様の貼り付けていただいたコードをじっくり勉強し(半年くらいかけて、、)ユーザー定義関数いっぱつで計算結果がでるようにしたいと思います。
みなさんありがとう御座いました。
No.3
- 回答日時:
こんにちは。
それは、練習のためですか?
もし、そうなら、自分なりに、少しお考えになって、レスを付けてください。こちらが解答を書いても、そうなんだ、というぐらいで、良いことではないと思います。たかがSUMでも、かなりハイレベルです。自分の実力に合わせてということになると思います。入門編を終えても、実際のSUM関数には程遠いです。
私は、VBA入門時に、ほとんど何も知らないまま、いきなり、SUMの関数と同じものを作ることになり、数時間考えて、なんとか考えて作りました。しかし、その後、SUMを観察すると、いろんなことが分かり、そのたびに修正をしてきました。
作る前には、よくSUM関数を観察しないとダメです。
SUMの挙動というのは、ダン・ブリックリン氏が作ったものだといわれますが、その後、Lotus社を経て、再び、Microsoft に戻ってきましたが、最初の挙動だけは、伝統的に残っています。
なぜ、SUM関数は、「文字列を0と数えるか?」というコラムを本で読んだことがあります。同系列の関数には、SUMPRODUCT関数 やPRODUCT 関数があります。
SUM関数の引数は、Range型ではなく、Variant 型で、おまけに、パラメータ配列となっています。だから、受けた引数をは最初に、どんな型になっているか判定しなければなりません。そして、その型によって、計算方法が変わります。単に、パラメータ配列にしても、その中に、Range型が入っていれば、そのままではエラーが発生してしまいます。また、循環参照を抜けるためには、どうしたらよいのか、配列数式の場合とか、難問がいくつかあります。
練習でなかったら、WorksheetFunction.Sum でよいと思います。
No.2
- 回答日時:
ANo.1さんのコードをお借りすると、
Function kei(ParamArray r() As Variant) As Long
Dim c As Variant
For Each c In r
kei = kei + c
Next
End Function
でいけるかと。
でも普通にワークシート関数でもいいような。
こんどは=kei(a1:b2)等に対応できなくなってしまいました。
ご回答ありがとうございました。
No1様とNo2様の回答を組み合わせると
望みのマクロができそうです。
No.1
- 回答日時:
Worksheet.Function.Sum()
ではだめですか?
自作するなら、
セル範囲の値をFor~Nextで合計していくだけです。
Function kei(r)
Dim c As Range
For Each c In r
kei = kei + c.Value
Next
End Function
この回答への補足
早速ありがとうございます
ためしてみたのですが、セル範囲が飛ぶと、、、つまり
=kei(a1,b2)
とするとエラーがでてしまいした。
それも対応させるためにはどうすればよいのでしょうか?
お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!
似たような質問が見つかりました
- Excel(エクセル) VBA SUM関数を入力したい 6 2022/08/20 20:10
- Excel(エクセル) エクセル、日々の集計整理方法。 1 2022/10/01 20:49
- Excel(エクセル) VBA オリジナル関数で選択セルの合計を作成したい 3 2023/03/19 19:45
- Excel(エクセル) エクセルでcsvファイルを開いてVBAを使いたい 7 2022/04/28 11:12
- Excel(エクセル) エクセルの数式を等間隔にオートフィルできるやり方を教えていただきたいです。 実際の作業↓ A3セルに 7 2023/06/05 19:04
- Excel(エクセル) エクセル 5 2022/07/06 14:19
- その他(データベース) 「1004:アプリケーション定義またはオブジェクト定義のエラー」への解消方法に関して 1 2023/07/09 11:47
- Excel(エクセル) エクセルで”入力シート”の文字書式の変更を”出力シート”で同じ文字書式で印刷したいです。VBA希望 4 2023/04/24 11:07
- Visual Basic(VBA) VBA初心者です。 VBAで行単位で条件付き書式の色をカウントしたいです。 大量のデータがあるExc 3 2022/06/08 10:00
- Visual Basic(VBA) VBA初心者です。 VBAで行単位で条件付き書式の色をカウントしたいです。 大量のデータがあるExc 3 2022/06/08 10:02
関連するカテゴリからQ&Aを探す
おすすめ情報
- ・漫画をレンタルでお得に読める!
- ・【大喜利】【投稿~11/22】このサンタクロースは偽物だと気付いた理由とは?
- ・お風呂の温度、何℃にしてますか?
- ・とっておきの「まかない飯」を教えて下さい!
- ・2024年のうちにやっておきたいこと、ここで宣言しませんか?
- ・いけず言葉しりとり
- ・土曜の昼、学校帰りの昼メシの思い出
- ・忘れられない激○○料理
- ・あなたにとってのゴールデンタイムはいつですか?
- ・とっておきの「夜食」教えて下さい
- ・これまでで一番「情けなかったとき」はいつですか?
- ・プリン+醤油=ウニみたいな組み合わせメニューを教えて!
- ・タイムマシーンがあったら、過去と未来どちらに行く?
- ・遅刻の「言い訳」選手権
- ・好きな和訳タイトルを教えてください
- ・うちのカレーにはこれが入ってる!って食材ありますか?
- ・おすすめのモーニング・朝食メニューを教えて!
- ・「覚え間違い」を教えてください!
- ・とっておきの手土産を教えて
- ・「平成」を感じるもの
- ・秘密基地、どこに作った?
- ・【お題】NEW演歌
- ・カンパ〜イ!←最初の1杯目、なに頼む?
- ・一回も披露したことのない豆知識
- ・これ何て呼びますか
- ・初めて自分の家と他人の家が違う、と意識した時
- ・「これはヤバかったな」という遅刻エピソード
- ・これ何て呼びますか Part2
- ・許せない心理テスト
- ・この人頭いいなと思ったエピソード
- ・牛、豚、鶏、どれか一つ食べられなくなるとしたら?
- ・好きなおでんの具材ドラフト会議しましょう
- ・餃子を食べるとき、何をつけますか?
- ・あなたの「必」の書き順を教えてください
- ・ギリギリ行けるお一人様のライン
- ・10代と話して驚いたこと
- ・大人になっても苦手な食べ物、ありますか?
- ・14歳の自分に衝撃の事実を告げてください
- ・家・車以外で、人生で一番奮発した買い物
- ・人生最悪の忘れ物
- ・あなたの習慣について教えてください!!
- ・都道府県穴埋めゲーム
デイリーランキングこのカテゴリの人気デイリーQ&Aランキング
-
VBA 変数名に変数を使用したい。
-
C#でbyte配列から画像を表示さ...
-
配列のペースト出力結果の書式...
-
Excelのメモリ(配列)の上限は2G...
-
定数配列の書き方
-
vba フィルター 複数条件 3つ以...
-
配列の中の最大値とそのインデ...
-
C#,繰り返し処理での最大値の取...
-
pictureboxの名前を変数で設定...
-
Dir関数で読み取り順を操作でき...
-
構造体配列内の文字列検索のよ...
-
VBAでMODE関数をつくる
-
構造体配列の特定のメンバーをF...
-
エクセルVBAからNotesでメー...
-
エクセルVBAで実行時エラー7、...
-
VBA 桁数が混在するソート
-
SUM関数の中身(VBA)
-
ASPのReDim Preserveについて
-
エクセルでXY座標に並べられた...
-
大量の変数を定義するにはどう...
マンスリーランキングこのカテゴリの人気マンスリーQ&Aランキング
-
VBA 変数名に変数を使用したい。
-
vba フィルター 複数条件 3つ以...
-
エクセルでXY座標に並べられた...
-
C#でbyte配列から画像を表示さ...
-
配列のペースト出力結果の書式...
-
配列の中の最大値とそのインデ...
-
Excel2010のinputboxで複数デー...
-
Dir関数で読み取り順を操作でき...
-
大量の変数を定義するにはどう...
-
Redim とEraseの違いは?
-
VB6のメモリ解放に関して
-
CheckBoxの配列化
-
COBOLの基本的な事なので...
-
コンボボックスのインデックス...
-
構造体配列の特定のメンバーをF...
-
構造体配列内の文字列検索のよ...
-
定数配列の書き方
-
Excelのメモリ(配列)の上限は2G...
-
Segmentation Fault (メモリ制限?)
-
複数のtextboxの処理を一括で行...
おすすめ情報