クラスモジュールの平均値を条件付きで算出する方法

このQ&Aのポイント
  • クラスモジュールを使用して、指定された条件に基づいて型番別の平均値を計算する方法について説明します。
  • 具体的には、C列に型番別の平均値を出力し、D列の日付を指定した範囲で平均値を計算します。
  • また、重要なポイントとして、同じ条件で計算された平均値が異なる年度間でも同じ数値になるようにする方法を紹介します。
回答を見る
  • ベストアンサー

クラスモジュールについて

下記のコードは型番別で数値1の平均値を型番別でC列に出すコードなのですが もう一つ条件を増やしてD列の日付を2011年〇〇月〇〇日~2012年〇〇月〇〇日まで といった感じで指定して平均値をだしたいのです。 重要なポイントなんですが、例えば下記データベースで2011年のすべてを対象とした場合 2011年で計算された平均値を2012年の方にも全く同じ数値になるようにしたいのです。 ぜひ、アドバイスお願いします。長文で申し訳ありません>< 正解例 A    B    C    D 型番 数値1  平均値  日付 1256  0.25  0.24   2011/1/1 1256  0.11  0.24   2011/3/2 1256  0.36  0.24   2011/5/3 2256  0.55  0.62   2011/10/4 2256  0.56  0.62   2011/11/5 2256  0.75  0.62   2011/12/6 1256  0.05  0.24   2012/2/1 1256  0.06  0.24   2012/4/2 1256  0.07  0.24   2012/6/3 2256  0.88  0.62   2012/9/4 2256  0.98  0.62   2012/11/5 2256  0.74  0.62   2012/12/6 不正解例 A    B    C    D 型番 数値1  平均値  日付 1256  0.25  0.24   2011/1/1 1256  0.11  0.24   2011/3/2 1256  0.36  0.24   2011/5/3 2256  0.55  0.62   2011/10/4 2256  0.56  0.62   2011/11/5 2256  0.75  0.62   2011/12/6 1256  0.05       2012/2/1 1256  0.06        2012/4/2 1256  0.07        2012/6/3 2256  0.88        2012/9/4 2256  0.98        2012/11/5 2256  0.74        2012/12/6 ' 標準モジュール Public Sub 平均値() Dim dct As Object Dim bot As Long Dim k As Variant Dim r As Long Dim itm As Class1 Set dct = CreateObject("Scripting.Dictionary") bot = Cells(Rows.Count, "A").End(xlUp).Row For r = 2 To bot k = CStr(Cells(r, "A").Value) If dct.Exists(k) Then Set itm = dct(k) Else Set itm = New Class1 dct.Add k, itm End If itm.Sum Cells(r, "B").Value Next For r = 2 To bot Cells(r, "C").Value = dct(CStr(Cells(r, "A").Value)).Avg() Next End Sub ' クラスモジュール(オブジェクト名「Class1」) Private total As Double Private cnt As Long Public Sub Sum(ByVal v As Double) total = total + v cnt = cnt + 1 End Sub Public Function Avg() As Double Avg = total / cnt End Function

質問者が選んだベストアンサー

  • ベストアンサー
  • 30246kiku
  • ベストアンサー率73% (370/504)
回答No.1

その指定した期間だけ計算して・・・ 以下 ★ 部分を追加してみました。 Public Sub 平均値()   Dim dct As Object   Dim bot As Long   Dim k As Variant   Dim r As Long   Dim itm As Class1   Const dtStart As Date = #1/1/2011# ' ★   Const dtEnd As Date = #12/31/2011# ' ★   Set dct = CreateObject("Scripting.Dictionary")   bot = Cells(Rows.Count, "A").End(xlUp).Row   For r = 2 To bot     If (Cells(r, "D") >= dtStart And Cells(r, "D") <= dtEnd) Then ' ★       k = Cells(r, "A").Value       If (dct.Exists(k)) Then         Set itm = dct(k)       Else         Set itm = New Class1         dct.Add k, itm       End If       itm.Sum Cells(r, "B").Value     End If ' ★   Next   For r = 2 To bot     k = Cells(r, "A").Value ' ★     If (dct.Exists(k)) Then ' ★       Cells(r, "C").Value = dct(k).Avg()     End If ' ★   Next   Set dct = Nothing ' ★ End Sub ※ Dictionary のキーの型は何でもよかったと思うので、CStr は省きました。 なお、クラスを使わなくても Dictionary に配列を設定すれば・・・・という例が以下 (上記よりチョピット速くなるかも) Public Sub 平均値2()   Dim dct As Object   Dim bot As Long   Dim k As Variant, v As Variant   Dim r As Long   Const dtStart As Date = #1/1/2011#   Const dtEnd As Date = #12/31/2011#   Set dct = CreateObject("Scripting.Dictionary")   bot = Cells(Rows.Count, "A").End(xlUp).Row   For r = 2 To bot     If (Cells(r, "D") >= dtStart And Cells(r, "D") <= dtEnd) Then       k = Cells(r, "A").Value       v = dct(k)       If (Not IsArray(v)) Then ReDim v(1)       v(0) = v(0) + Cells(r, "B").Value       v(1) = v(1) + 1       dct(k) = v     End If   Next   For r = 2 To bot     v = dct(Cells(r, "A").Value)     If (IsArray(v)) Then Cells(r, "C").Value = v(0) / v(1)   Next   Set dct = Nothing End Sub 不都合あれば修正してください。

ryutahayashi
質問者

お礼

大変遅くなり、ごめんなさい。 お礼をしてたつもりがちゃんと出来てませんでした。 その節はありがとうございました。

関連するQ&A

  • クラスモジュールについて

    下記のコードは平均値を出すコードを作ったのですが、B列に文字列を含むとエラーになってしまいます。なのでB列に数字以外のものが入っている状態でも動くようにしたいのですが、お詳しい方アドバイスお願いします。 ' 標準モジュール Public Sub 平均値() Dim dct As Object Dim bot As Long Dim k As Variant Dim r As Long Dim itm As Class1 Set dct = CreateObject("Scripting.Dictionary") bot = Cells(Rows.Count, "A").End(xlUp).Row For r = 2 To bot k = CStr(Cells(r, "A").Value) If dct.Exists(k) Then Set itm = dct(k) Else Set itm = New Class1 dct.Add k, itm End If itm.Sum Cells(r, "B").Value Next For r = 2 To bot Cells(r, "C").Value = dct(CStr(Cells(r, "A").Value)).Avg() Next End Sub ' クラスモジュール(オブジェクト名「Class1」) Private total As Double Private cnt As Long Public Sub Sum(ByVal v As Double) total = total + v cnt = cnt + 1 End Sub Public Function Avg() As Double Avg = total / cnt End Function

  • 検索マクロ

    下記のマクロは、検索文字でシートを検索し、そのセルアドレス情報を シートを追加して表示する機能ですが、BOOK全体に検索し、シート名を含めて表示するには、xxxxのところをどのように変更すればいいか。よろしくお願いします。 Sub kennsaku_Macro1() Dim ret Dim r As Range Dim adr As String Dim cnt As Long Dim psw As Boolean Dim mySht, adSht, ws As Worksheet Set mySht = ActiveSheet ret = Application.InputBox("検索文字列を入力してください") If TypeName(ret) <> "Boolean" Then With mySht.Cells Set r = .Find(ret, LookIn:=xlValues, lookat:=xlPart) If Not r Is Nothing Then adr = r.Address cnt = 2 '2行目から表示 xxxxxxxxxxxxx For Each ws In Worksheets If ws.Name = "検索結果" & ret Then psw = True Exit For End If Next ws If psw Then Set adSht = ws adSht.Cells.ClearContents Else Set adSht = Worksheets.Add adSht.Name = "検索結果" & ret End If adSht.Cells(cnt, 1).Value = r.Value adSht.Cells(cnt, 2).Value = xxxx 'シート名 adSht.Cells(cnt, 3).Value = adr Do Set r = .FindNext(r) If r.Address = adr Then Exit Do Else cnt = cnt + 1 adSht.Cells(cnt, 1).Value = r.Value adSht.Cells(cnt, 2).Value = xxxx 'シート名 adSht.Cells(cnt, 3).Value = r.Address End If Loop End If End With End If adSht.Cells(1, 1).Value = "項目" adSht.Cells(1, 2).Value = "シート名" adSht.Cells(1, 3).Value = "セルアドレス" mySht.Activate End Sub

  • エクセルVBAで

    登録ボタンを作りたいのですが うまくいきません。 応答無しになってしまいます。 仕事でコードを入力して、住所やその他の関連事項を 登録して、検索し、封筒に宛名印刷し、登録内容の修正をしたいと思っています。 登録ボタンは下記のようなものを作りました。 Private Sub CommandButton1_Click() Dim bk As Workbook Dim sh1 As Worksheet Dim sh2 As Worksheet Dim cnt1 As Long Set bk = ThisWorkbook Set sh1 = bk.Worksheets("現場登録検索") Set sh2 = bk.Worksheets("一覧") cnt1 = 6 Do While sh2.Cells(cnt1, 2).Value <> "" cnt = cnt1 + 1 Loop '得意先CD sh2.Cells(cnt1, 2).Value = sh1.Cells(2, 3).Value '現場CD sh2.Cells(cnt1, 3).Value = sh1.Cells(3, 3).Value '送り方 sh2.Cells(cnt1, 22).Value = sh1.Cells(4, 3).Value '封筒 sh2.Cells(cnt1, 23).Value = sh1.Cells(5, 3).Value MsgBox "登録できました。" End Sub 何が悪いのでしょうか? よろしくお願い致します。

  • VBA Do~Loopについて

    VBA勉強中です。 マクロの作成は完了しているのですが、処理効率について指摘を受け、 その際に助言もいただいたのですが、自身の勉強不足、理解不足で どのように変更すれば良いのか分からず、教えていただきたいです。 Do While Ax2 <= 30 で30回繰り返すのではなく (Cells(Ax2,"B").Value <> "" ) の間繰り返すように変更したいです。 ---------------- Sub test()  Dim File1(30) As string  Dim Sheet1(30) As string  Dim Sheet2(30) As string  Dim Cnt As Integer  Ax1=1  Ax2=7  Do While Ax2 <= 30    If Cells(Ax2, "B").Value <> "" Then     File1(Ax1) = Cells(Ax2, "B").Value     Sheet1(Ax1) = Cells(Ax2, "C").Value     Sheet2(Ax1) = Cells(Ax2, "D").Value     Cnt =Ax1    End If    Ax1 = Ax1 + 1    Ax2 = Ax2 + 1  Loop End Sub ---------------- お手数ですが、よろしくお願いいたします。

  • ThisWorkBookモジュールとSheetモジュールの両立

    エクセル2003でマクロを組んでいます。 Sheet1,Sheet2の2つのシートがあり、 片方のシートの"A4:G10"の範囲に値を書き込むと、もう片方の同じ位置に同じ値が書き込まれるようなマクロを組みたいです。 以前ここで教えていただいたものを改変して以下を作りました(ThisWorkBookモジュールです)。 Private Sub Workbook_SheetChange(ByVal Sh As Object, ByVal Target As Range) Dim r As Range Dim Num As Integer Dim S As String, Sh_name As String Sh_name = ActiveSheet.Name Set r = Intersect(Target, Range("A4:G10")) If Not (r Is Nothing) Then Application.EnableEvents = False For Num = 1 To 2 S = "Sheet" & Num If S <> Sh_name Then Worksheets(S).Range(r.Address).Value = r.Value End If Next Application.EnableEvents = True End If End Sub ここまでは正常に動作します。 また、 Sheet1とSheet2のモジュールに、 A列のセルに値が入力された場合、同じ行のC列のセルの色を塗るという記述をしています。 Private Sub Worksheet_Change(ByVal Target As Range) If Target.Column = 1 Then Cells(Target.Row, 3).Interior.ColorIndex = 5 End If End Sub これらを同時に生かしたいのですが、 どのように書けばいいでしょうか。 EnableEvents = False/Trueを消してしまうと、 Worksheets(S).Range(r.Address).Value = r.Valueが実行されるたびにThisWorkBookモジュールが動いているようです。 そして2回目のSet r = Intersect(Target, Range("A4:G10"))でエラーが出ます。 (エラーは出ずとも延々と(無限ではない回数)ThisWorkBookモジュールを繰り返したコードもありました。) よろしくお願いします。

  • VBAtest

    VBAおn以下の Sheets("OP").Select Dim atai As String atai = Cells(2, 2).Value Dim datedata(40) As String For j = 0 To 40 If Cells(j + 3, 2).Value = "" Then Else datedata(j) = Cells(j + 3, 2).Value End If Next Dim shihyou As String For i = 1 To 2 shihyou = Cells(2, i + 2).Cells.Value Sheets(shihyou).Select Dim tmp_c As Integer For r = 1 To 10 tmp_c = 0 For c = 1 To 10 If tmp_c = 0 Then If Sheets(shihyou).Cells(r, c).Value = atai Then tmp_c = c End If Else Dim vals(40) As String For k = 0 To 40 For l = 1 To r + 41 For m = 1 To tmp_c - 1 If Sheets(shihyou).Cells(l, m).Value = datedata(k) Then vals(k) = Sheets(shihyou).Cells(l, tmp_c).Value End If Next Next Next End If Next Next Sheets("OP").Select For k = 3 To 43 Cells(k, i + 2).Value = vals(k - 3) Next Next End Sub

  • シード権を省いたヒートランダム分け

    A1は名前が並んでいます。 B1はシード権取得の名前です。 C1はA1セルの人数に合わせてヒート分けする数を入力します。1つのヒートに4名前後です。 Dセル以降はシード権を省いたヒート分けします。 下記はA1セルからランダムにヒート分けしたプログラムです。 シード権を省いたヒートランダム分けをするにはどうしたら良いでしょうか? 宜しくお願いします。 Sub heatrandom() Dim Total As Integer Dim TableCnt As Integer Dim Data1 As Variant Dim Data2() As String Dim i As Integer, j As Integer, k As Integer Dim FirstRow As Long, LastRow As Long FirstRow = 2 LastRow = Cells(Rows.Count, 1).End(xlUp).Row Total = LastRow - FirstRow + 1 TableCnt = Range("B2").Value Data1 = Range(Cells(FirstRow, 1), Cells(LastRow, 1)).Value ReDim Data2(1 To Total) Randomize For i = Total To 1 Step -1 j = Int(Rnd * i) + 1 Data2(i) = Data1(j, 1) Data1(j, 1) = Data1(i, 1) Next i i = 1 Do For j = 1 To TableCnt k = k + 1 Cells(i, j + 2).Value = Data2(k) If k = Total Then Exit Sub Next j i = i + 1 Loop End Sub

  • VBA リーダーを選出したチーム分け

    名簿を作り、その名前をランダムでチームに分けるようにしたいです。 検索して以下のようなVBAを作成しました。 ※ チーム数は「TmCnt = 5」 Sub Sample() Dim Total As Integer Dim TmCnt As Integer Dim Data1 As Variant Dim Data2() As String Dim i As Integer, j As Integer, k As Integer Total = Cells(Rows.Count, 1).End(xlUp).Row TmCnt = 5 Data1 = Range("A1:A" & Total).Value ReDim Data2(1 To Total) Randomize For i = Total To 1 Step -1 j = Int(Rnd * i) + 1 Data2(i) = Data1(j, 1) Data1(j, 1) = Data1(i, 1) Next i i = 1 Do For j = 1 To TmCnt k = k + 1 Cells(i, j + 2).Value = Data2(k) If k = Total Then Exit Sub Next j i = i + 1 Loop End Sub 問題はA1~A5までの名前をランダムにリーダーとして各チームの1番目に配置する方法はどうしたら良いでしょうか? 宜しくお願いします。

  • macroについて教えてください

    こんにちは。以前こちらでPrivate SubについてMacroを教えていただきました。(あの後ログインパスワード等が不明になりお礼も出来ませんでしたが。。。回答頂いた方すみませんでした。) 下記がそのMacroですが、今回また少し変えることになり どのように変えていいのか分かりません。 前回は1~5はグレー、6~10は茶色・・・という形にしたのですが 今回は進捗率での管理をしたく、80%以下は白、80~90%は赤、90~100%は青としたいと思っています。 Private Sub Worksheet_Change(ByVal Target As Range) Dim iColors As Variant Dim rw As Long Dim CellCnt As Integer Dim col As Integer Dim col2 As Integer Dim i As Integer Dim j As Integer Dim k As Integer Dim c As Variant Dim ar() As Variant Dim Sh1 As Worksheet Set Sh1 = Worksheets("小児科Dr") col = Target.Cells(1).Column '制限された列 If Not (col = 4 Or col = 8 Or col = 12 Or col = 16) Then Exit Sub iColors = Array(16, 16, 16, 16, 16, 53, 53, 53, 53, 53, 54, 54, 54, 54, 54) CellCnt = Target.Count ReDim ar(CellCnt - 1) For Each c In Target If c.Value <> "" Then If IsNumeric(c.Value) Then i = c.Value If i >= 11 Then i = 10 End If If i > 0 And i < 11 Then j = iColors(i - 1) Else j = 2 End If ar(k) = j k = k + 1 End If End If Next c rw = Target.Row Select Case col Case 4: col2 = 2 Case 8: col2 = 8 Case 12: col2 = 14 Case 16: col2 = 20 'Sh1.Cells(rw + 2, 13).Resize(Int(Target.Count / 3), 3).Interior.ColorIndex = j End Select InsideColors Sh1, rw, col2, CellCnt, ar() Set Sh1 = Nothing End Sub Private Sub InsideColors(sh As Worksheet, _ rw As Long, _ col As Integer, _ cnt As Integer, _ ar As Variant) 'sh[シート],rw[行], col[列],cnt[セル個数],iColor[色指数] Dim i As Integer Dim j As Integer Dim n As Integer Dim k As Integer If cnt Mod 5 > 0 Then '範囲行数 i = (cnt + 5 - (cnt Mod 5)) / 5 Else i = cnt / 5 End If rw = Int((rw - 1) / 5) + 1 '行再設定 j = ((rw - 1) Mod 5) + 1 '列設定 For n = j To cnt sh.Cells(rw + 2, col).Resize(i, 5).Cells(n).Interior.ColorIndex = ar(k) k = k + 1 Next n End Sub 毎回他の人を頼ってしまい、申し訳ないのですがお願いします。 また、前回分からなかったので1~5を指定するときに5回同じカラー番号を書いたのですがこちらも良かったら手直し方法を教えていただければ助かります。 宜しくお願いします。

  • エクセル2019 VBAについて

    エクセル2019でVBAを使いコピーペーストの勉強中です、次の箇所(Dim i As integr)で、ユーザー定義型は定義されていませんと指摘されて止まってしまします、Sheet("データ")には3行のデータは入っています、VBA初心者のため、この後が、なかなか前に進めません、どうかよろしくおねがいします。 ********************************** Sub 練習() Dim s1 As Worksheet: Set s1 = Worksheets("請求書") Dim s2 As Worksheet: Set s2 = Worksheets("データ") Dim r1 As Integer: r1 = 18 Dim r2 As Integer: r2 = 2 { Dim i As integr } For i = 0 To 2 s1.Range(s1.Cells(r1 + i, 1), s1.Cells(r1 + i, 3)).Value = s2.Range(s2.Cells(r2 + i, 2), s2.Cells(r2 + i, 4)).Value s1.Cells(r1 + i, 4).Value = s1.sells(r1 + i, 2).Value * s1.Cells(r1 + i, 3).Value Next End Sub ***************************************

専門家に質問してみよう