- ベストアンサー
Scripting.Dictionaryについて
- VBAでScripting.Dictionaryを使用してリストボックスに値を代入するコードを理解できない
- リストボックスに値を代入する際に、重複を除いて順番に代入される
- オートフィルタで抽出した値をScripting.Dictionaryに格納してリストボックスに代入する
- みんなの回答 (2)
- 専門家の回答
質問者が選んだベストアンサー
>'8行目の値 >'9行目の値を入れたい それぞれ、H列、I列、という事ですね。混乱するので行と列の区別はつけましょう。 さて、『vの値が重複を除いて、順番にリストに入る動作』という事ですが、 仮に H列 I列 A B A B A C A C というデータの時は、ListBoxの抽出はどうしますか? それによって書き方が変わってきます。 パターン1)H列のみ基準。 A B,C 4 パターン2)H,I列複合基準。 A B 2 A C 2 パターン1の場合、DictionaryのItemを配列にする方法が考えられます。 具体的には、 変数 Dim ary As Variant を追加して For i = 0 To UBound(v) - 1 'H列値が既に登録されていればI列値を","区切りで追加しカウントアップする If .exists(v(i)) Then '登録済みのItemの内容を一旦配列に取得 ary = .Item(v(i)) 'I列値が既に登録されていれば追加はしない If InStr(ary(0), x(i)) = 0 Then ary(0) = ary(0) & "," & x(i) End If 'カウントアップ ary(1) = ary(1) + 1 '追加した配列をItemに戻す .Item(v(i)) = ary 'H列値が登録されてなければItemに登録 Else .Item(v(i)) = Array(x(i), 1) End If Next ReDim myList(1 To .Count, 2) i = 0 For Each v In .Keys i = i + 1 myList(i, 0) = v 'H列の値 myList(i, 1) = .Item(v)(0) 'I列の値 myList(i, 2) = .Item(v)(1) 'H列値のカウント数 Next パターン2の場合、DictionaryのKeyをH,I列の複合キーにしてあとで分割します。 Dim ary As Variant を追加して Set CC = RR.Columns("H:I") ': '省略 ': Application.Intersect(CC, CC.Offset(1)).Copy 'H,I列をコピー With New DataObject .GetFromClipboard v = Split(.GetText, vbCrLf) 'vに代入 End With With CreateObject("Scripting.Dictionary") For i = 0 To UBound(v) - 1 .Item(v(i)) = .Item(v(i)) + 1 Next ReDim myList(1 To .Count, 2) i = 0 For Each v In .Keys i = i + 1 'キーをvbTabで分割 ary = Split(v, vbTab) myList(i, 0) = ary(0) 'H列の値 myList(i, 1) = ary(1) 'I列の値 myList(i, 2) = .Item(v) 'H,I列値のカウント数 Next ': '省略 その他のアドバイスとして。 ComboBox1_Change イベントは考え直したほうが良いです。 カーソルキーでドロップダウンリストを変更する度にイベントが実行されてしまいます。 _AfterUpdateイベントや_Exitイベント、または他のコントロールのイベントなどが良いでしよう。 また、変数宣言をまとめるなら Dim i As Long, ii As Long としないと >Dim i, ii As Long これだと i は Variant型で宣言されている事になります。 また、Dictionaryについて理解できない場合、 AdvancedFilterメソッドや関数などを使って、一旦作業用シートにデータを作成し、 そこからListBoxに取り込むようにしても良いかもしれませんね。
その他の回答 (1)
- end-u
- ベストアンサー率79% (496/625)
Set CC = RR.Columns("H:I") Set SS = RR.Columns("J") ...として ': Application.Intersect(CC, CC.Offset(1)).Copy With New DataObject .GetFromClipboard v = Split(.GetText, vbCrLf) Application.Intersect(SS, SS.Offset(1)).Copy .GetFromClipboard x = Split(.GetText, vbCrLf) End With With CreateObject("Scripting.Dictionary") For i = 0 To UBound(v) - 1 If .exists(v(i)) Then ary = .Item(v(i)) ary(0) = ary(0) + CDbl(x(i)) ary(1) = ary(1) + 1 .Item(v(i)) = ary Else .Item(v(i)) = Array(CDbl(x(i)), 1) End If Next ReDim myList(1 To .Count, 3) i = 0 For Each v In .Keys i = i + 1 'キーをvbTabで分割 ary = Split(v, vbTab) myList(i, 0) = ary(0) 'H列の値 myList(i, 1) = ary(1) 'I列の値 myList(i, 2) = .Item(v)(0) 'J列の計 myList(i, 3) = .Item(v)(1) 'H,I列値のカウント数 Next ': こんな感じでしょうか。 パターン1と2の組み合わせですね。 J列値のエラー対策など、いろいろ工夫してみてください。 "Scripting.Dictionary"の基本についてなら以下参考。 http://msdn.microsoft.com/ja-jp/library/cc428065.aspx http://www.geocities.jp/cbc_vbnet/Scripting/dictionary.html では、私はこの辺で。がんばってください。 #今回のケースだと、ピボットテーブルを応用したほうが良さそうな気がしなくもないけど。
お礼
end-uさん 貴重なアドバイスありがとうございました。 いろいろ工夫しながら動作を覚えていきたいと思います。
補足
end-uさん ご回答ありがとうございます。 パターン2が私のやりたかったことです。 問題なく動作しました。 本当にありがとうございます。 Dictionaryを理解できれば、いろいろと応用範囲が 広がると思い、日々動作を検証しています。 ちなみに Set CC = RR.Columns("H:I")を Set CC = RR.Columns("H:J")にし、 ReDim myList(1 To .Count, 3) i = 0 For Each v In .Keys i = i + 1 'キーをvbTabで分割 ary = Split(v, vbTab) myList(i, 0) = ary(0) 'H列の値 myList(i, 1) = ary(1) 'I列の値 myList(i, 2) = ary(2) 'J列の値の合計 myList(i, 3) = .Item(v) 'H,I列値のカウント数 Next '省略 のようにしたい場合、ary(2)を 下記の場合はカウントですが、 For i = 0 To UBound(v) - 1 .Item(v(i)) = .Item(v(i)) + 1 Next 値の集計をさせることはできるのでしょうか? ここまで動作が理解できれば、試してみたいことが あるので、よろしくお願いします。