ここから本文です

(VBA) Dictionary(3次元) でうまく集計できません。 A2:E5にある4行の入会...

sunshellsalohaさん

2014/9/614:08:11

(VBA)
Dictionary(3次元) でうまく集計できません。

A2:E5にある4行の入会データから
地区,都道府県,月別に件数集計をしています。

(但し、地区,都道府県,年月、企業の4項目全てが重複している場合は1件)

本件集計の方法は他に多々あるとは思いますが
Dictionary(連想配列)"を使う方法に限定しています。

Dictionaryのキー,アイテムは次の通りです(ネストの内側DIC3から)
●DIC3:
キー=入会年月1日
アイテム=件数
●DIC2:
キー=都道府県,
アイテム=DIC3
●DIC1:
キー=地区
アイテム=DIC2
です

DIC1(DIC2(DIC3)))のように3重に囲まれているイメージです。
DIC4は, 発生年月を集約するために利用

●例示すると以下の構成をイメージしてます
関東
ー東京
ーー2014/07/01,2
ーー2014/06/01,1
ー神奈川
ーー2014/08/01,1

テストデータの場合の集計値は
G1:K5の出力表の通りですが、そうなりません。

●なお、集計ルーチンは実行時エラーにならずに終了はしますので
何か、ロジック抜けと思われますが、原因を収束出来かねてます。

環境その他は以下の通りです。

●XLは97VBAです。
●Dictionaryはテストベースなので,"As New Dictionary "として
先行定義
●ウオッチやイミーディエートでうまく集計データを掴まえる
ことが出来ず、集計ミスは明白ですが、現在、集計値がいくつか
、はっきりしてません。


コードは結局、長くなっているので、"SUM9X"として
テキストとして公開中ですので,ダウンロード後、VBEに貼り付けて下さい

公開:= http://yahoo.jp/box/VhWOXz

どこを、どのように訂正すれば、正しく件数集計ができますでしょうか?
よろしくご教示下さい

以上

DIC2,DIC3,イミーディエート,Level1,DIC1,SUM9X&quot,Level2

閲覧数:
1,694
回答数:
2
お礼:
25枚

違反報告

ベストアンサーに選ばれた回答

2014/9/709:47:41

基本的にはDictionaryのItemの方を新たなDictionaryにすればいいと思います。
と言うので作ってみたのですが、なんだかごちゃごちゃしてしまいました。
もう少しスマートにできるかと思います。

(私が)簡略化してわかり易いために、レベル1からレベル3のキーワードにしています。
Level1が地域、Level2が都道府県、Level1が日付です。
入会の◎の部分は省略してます。
作表も省略しています。



Sub sample()
Dim ws As Worksheet
Dim lastRow As Long
Dim r As Long
Dim dic As New Dictionary
Dim level1 As String
Dim level2 As String
Dim level3 As String
Dim d1 As Dictionary
Dim d2 As Dictionary
Dim d3 As Dictionary
'
Set ws = Sheets("Sheet1")
lastRow = ws.Range("A" & Rows.Count).End(xlUp).Row
For r = 2 To lastRow
level1 = Cells(r, 1).Value '地域
level2 = Cells(r, 2).Value '都道府県
level3 = Cells(r, 4) - Day(Cells(r, 4)) + 1 '日付
'レベル1のキーを持っているかチェック
'持っていなければレベル2とレベル3のキーの空のデータを作成してレベル1のキーで追加
If Not dic.Exists(level1) Then
Set d3 = New Dictionary
d3.Add level3, 0
Set d2 = New Dictionary
d2.Add level2, d3
dic.Add level1, d2
End If
'この時点でレベル1のキーは必ず持っている
'レベル2のキーを持っているかチェック
'持っていなければレベル3のキーの空のデータを作成してレベル2のキーで追加
If Not dic(level1).Exists(level2) Then
Set d3 = New Dictionary '新たな空のDictionary(レベル3用)
d3.Add level3, 0 '個数0を設定
dic(level1).Add level2, d3
End If
'この時点でレベル2のキーは必ず持っている
'レベル3のキーを持っているかチェック
'持っていなければ空のデータ(0個)をレベル3のキーで追加
If Not dic(level1)(level2).Exists(level3) Then
dic(level1)(level2).Add level3, 0
End If
'この時点で全レベルのキーがある
dic(level1)(level2)(level3) = dic(level1)(level2)(level3) + 1
Next

'結果
Dim msg As String
Dim i1 As Integer
Dim i2 As Integer
Dim i3 As Integer
Dim keys1 As Variant
Dim keys2 As Variant
Dim keys3 As Variant
Dim items3 As Variant
keys1 = dic.Keys
For i1 = 0 To dic.Count - 1
keys2 = dic(keys1(i1)).Keys
For i2 = 0 To dic(keys1(i1)).Count - 1
keys3 = dic(keys1(i1))(keys2(i2)).Keys
items3 = dic(keys1(i1))(keys2(i2)).Items
For i3 = 0 To dic(keys1(i1))(keys2(i2)).Count - 1
msg = msg & keys1(i1) & "-" & keys2(i2) & "-" & keys3(i3) & "-" & items3(i3) & vbCrLf
Next
Next
Next
MsgBox msg
End Sub

  • 質問者

    sunshellsalohaさん

    2014/9/717:38:41

    先ず,一報(^^)

    blue_arlequinさまロジックに組み替え,集計出来ました。

    dic構成への考え方が似ていたので,当方案でも可能かな?と
    再トライしたけどXでしたが

    dic2,dic3をSet文にしたら当方ロジックでもクリア出来ました。

    原因もほぼ推定出来たようです

    ◆RemoveAll <> Set dic = New Dictionaryの差で結果反映せず

    結果数値は
    東京:1,2,0 神奈川:0,0,1ではなく
    東京:0,0,1 神奈川:△,△,1
    でした。

    dicやVBAに経験浅く,Dictionaryを一々,Setでインスタンスを
    作りたくなかったので,敢えてRemoveAllを切り替えたら
    システム的にグチャグチャでした(^^)

    //

  • その他の返信(2件)を表示

返信を取り消しますが
よろしいですか?

  • 取り消す
  • キャンセル

質問した人からのコメント

2014/9/11 16:04:58

結局,課題の直接解決という視点でbaを選ばせていただきました。

が、お二人には甲乙付け難い評価値と考えてます。

本当にありがとうございました。

//

ベストアンサー以外の回答

1〜1件/1件中

2014/9/705:54:23

前回の質問でも回答させていただいたものです。
前回でも簡単に説明しましたが、このようなDictionaryの使い方では、多次元配列のようには使えないと思います。DIC1、DIC2は配列の値の同じ一次元配列が並んでいるだけです。
例えばDIC2のKey「東京」のItemはDIC3となっているので、その中身は「Key=Item」で表すと「2014/06/01=1」「2014/07/01=2」「2014/08/01=1」というDictionaryになりますし、同じようにDIC2のKey「神奈川」も「2014/06/01=1」「2014/07/01=2」「2014/08/01=1」というDictionaryになります。(正しく集計出来ているとして)
例えばArr1(5)という配列全てに、Arr2(2)という配列が入っていたとするとArr1()のインデックスはいくつでもArr2(5)が返ってきます。そうなるとArr1()の配列の必要が無い気がします。
例)Arr2()の内容がArr2(0)=0、Arr2(1)=1、Arr2(2)=2とすると
Arr1(0)(2)=2ですしArr1(3)(2)=2、Arr1(5)(2)=2となります。

普通の配列の場合は各配列内の値が同じ配列だったとしても意味があるかもしれませんが、連想配列の場合、全てのKeyで同じ配列をItemにする意味が無いような気がします。

なのでDictionaryのItemでDictionaryを使う場合はItemのDictionaryを配列で扱うのがいいと思います。
DIC1.Add key1,DIC2(0)
DIC1.Add key2,DIC2(1)
DIC2(0).Add key1,DIC3(0)
DIC2(0).Add key2,DIC3(1)
こすればDIC1(key1)(key1)とDIC1(key1)(key2)で違うDictionary( DIC3(0)とDIC3(1) )を使えるので集計に使えると思います。

返信を取り消しますが
よろしいですか?

  • 取り消す
  • キャンセル

あわせて知りたい

みんなで作る知恵袋 悩みや疑問、なんでも気軽にきいちゃおう!

5文字以上入力してください

Q&Aをキーワードで検索:

Yahoo! JAPANは、回答に記載された内容の信ぴょう性、正確性を保証しておりません。
お客様自身の責任と判断で、ご利用ください。
本文はここまでです このページの先頭へ

「追加する」ボタンを押してください。

閉じる

※知恵コレクションに追加された質問は選択されたID/ニックネームのMy知恵袋で確認できます。