EXCEL VBAでDictionaryオブジェクトを宣言する方法と違いについて

このQ&Aのポイント
  • EXCEL VBAでDictionaryオブジェクトを宣言する方法には4つの違いがあります。
  • 4つの宣言方法は、オブジェクト型、バリアント型、Newキーワードを使った宣言方法です。
  • オブジェクト型の宣言は、Dimステートメントでオブジェクトを宣言し、CreateObject関数でオブジェクトを作成します。
回答を見る
  • ベストアンサー

EXCEL「Dictionaryオブジェクト」宣言

EXCEL VBAにて Dictionaryオブジェクトを利用しようと思い ネット検索して調べていると・・・ 1)Dim MyDic As Object Set MyDic=CreateObject("Scripting.Dictionary") 2) Dim MyDic As Scripting.Dictionary Set MyDic = New Scripting.Dictionary 3) Dim MyDic Set MyDic=CreateObject("Scripting.Dictionary") 4) Dim myDic As New Scripting.Dictionary 上記の4パターンが出てきました。 いずれも「連想配列」を使うものなのですが、 オブジェクト型、バリアント型、Newキーワードで宣言・・・ 4つの違いがイマイチ理解できません。 違いを教えてください。

  • mi-tan
  • お礼率68% (251/366)

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

  • ベストアンサー
  • nicotinism
  • ベストアンサー率70% (1019/1452)
回答No.2

1)Dim MyDic As Object Set MyDic=CreateObject("Scripting.Dictionary") 参照設定無しで扱う場合 2) Dim MyDic As Scripting.Dictionary Set MyDic = New Scripting.Dictionary 有りで・・ 3) Dim MyDic Set MyDic=CreateObject("Scripting.Dictionary") 無しで 4) Dim myDic As New Scripting.Dictionary 有りで だけでは分からないので、用途・環境の面で考えてみました。 今回の場合は、Scripting.Dictionary なのでWindows2000の頃からバージョンは変わっていないので 説明しやすくするために、AccessからExcelをオートメーションで扱う例で説明します。 Scripting.Dictionary → Excel.Applicationです。 Excelに参照設定を行う場合はバージョンによって、Microsoft Excel xx.x Object Libraryの xx.x が変わってくるのはご存知かと思います。 参照設定を行ってコーディングすれば、Excelのプロパティなどが自動表示されるので非常に楽ちんです。 Excelの定数もそのまま使えます。 ただ、2003に参照設定して作成したものを2010がインストールされている環境で使おうとした時など 参照設定不可になりますので、改めて設定しなおす必要があります。 一方無しでコーディングするのは上記お助け機能が使えないので手間ですが バージョンが異なってもある程度は差異を吸収してくれます。 なので不特定のPCで使う場合は、有りで作成し、最終的に無しで動くように変更しています。 自身で使われるだけでしたら、2)で良いかとも思います。 (Scripting.Dictionary自体Windows2000?の頃から変わっていないし) 3)については、VBScript がこのパターンです。 (元々変数の型宣言ができないので。) VBAではVariant型で宣言したものを再度Setでやり直しているので二度手間です。 4)は2)を1行にまとめたものですが 2)の場合は、Set・・した時点でインスタンスが作成されますが 4)は参照しに行って初めて作成されます。 また、Set ・・ Nothing で 2)は解放され以後は使えなくなりますが 4)はNothingした後でも参照しに行けばゾンビのごとく新たに立ち上がります。 以下のをローカルウィンドウかウォッチウィンドウで確認しつつ実行してみてください。 1行目と2・3行目のコメントアウトを入れ替えてみた場合も。 Sub DicTest() Dim myDic As New Scripting.Dictionary 'Dim myDic As Scripting.Dictionary 'Set myDic = New Scripting.Dictionary Stop myDic.Add 0, "zero" myDic.Add 1, "one" Debug.Print "count1=" & myDic.Count Debug.Print myDic(1) Set myDic = Nothing Stop Debug.Print "count2=" & myDic.Count 'ゾンビ?復活 Stop End Sub 余計わけわかんなくなったらゴメン。

mi-tan
質問者

お礼

基本的に不特定多数のPC、かつExcelのバージョンも違うんで 個々で参照設定はしない(出来ていない)前提で 作りたいと思っていました。 >なので不特定のPCで使う場合は、有りで作成し、最終的に無しで動くように変更しています。 すみません、ちょっと具体的な手法が解らなくなりました 参照設定なしの状態ならば・・・1)が一番、無難でしょうか?

その他の回答 (3)

  • kumatti1
  • ベストアンサー率60% (73/121)
回答No.4

VarType関数があるのは忘れてました。 Variant型はこの辺を参照。

参考URL:
http://www5f.biglobe.ne.jp/~f-lap/tips_staticarray.htm
mi-tan
質問者

お礼

ん~私には・・・難しいです。 でも、勉強になる情報もあり、 ぜひ参考にします。 ありがとうございました。

  • nicotinism
  • ベストアンサー率70% (1019/1452)
回答No.3

具体的な手法も何もありません。 参照設定しておいて問題なく機能するのを確認後に 参照設定のチェックを外して Dim myDic As New Scripting.Dictionary ↑コメントアウト ↓コメントを外す 'Dim myDic As Scripting.Dictionary 'Set myDic = New Scripting.Dictionary コンパイルや実行時エラーが出ないようにチマチマと修正。 ・・・と私はやっています。 Dictionaryなら修正の必要はなさそうですね。 >参照設定なしの状態ならば・・・1)が一番、無難でしょうか? 1)しかありません。

mi-tan
質問者

お礼

すみません。 コメントをつけたり、はずしたりする意味だったんですね 1)しかないですよね。 本当にありがとうございました。 今からコーディングに励みます

  • kumatti1
  • ベストアンサー率60% (73/121)
回答No.1

> 1)Dim MyDic As Object 実行時バインド > 2) Dim MyDic As Scripting.Dictionary 事前バインド > 3) Dim MyDic 実行時バインド (Variant型のvtメンバがVT_DISPATCH) > 4) Dim myDic As New Scripting.Dictionary 事前バインド (参照セット時のもたつきがある) 速度的には 2 - 4 - 1 - 3 の順かなと。 事前バインドの 2 と 4 はメソッドやプロパティの呼び出し時には差がありませんが、実行時バインドの 1 と 3 は理論上、明確な差があります。 (体感出来る程でないにしても)

mi-tan
質問者

お礼

バイディングがイマイチ整理できてなかったので とても参考になりました >Variant型のvtメンバがVT_DISPATCH これについては、勉強不足で・・・ ちょっと調べてみましたが、すぐに理解できず・・・ 頑張って勉強します ありがとうございました

関連するQ&A

  • エクセルVBAでDictionaryオブジェクトについて

    エクセル2000です。 教えてください。 http://www.eurus.dti.ne.jp/~yoneyama/Excel/vba/vba_dictionary.html というサイトで  「myDic.Add Cells(i, 1).Value, Cells(i, 2).Value は   myDic(Cells(i, 1).Value) = Cells(i, 2).Value と書くこともできます。 」 という記述を見つけました。 試してみたところ Sub test01() Dim myDic As Object Dim myAr() Set myDic = CreateObject("Scripting.Dictionary") For i = 2 To 7 If Not myDic.exists(Cells(i, 1).Value) Then myDic.Add Cells(i, 1).Value, Cells(i, 2).Value End If Next i myAr() = myDic.Keys MsgBox Join(myAr()) End Sub Sub test02() Dim myDic As Object Dim myAr() Set myDic = CreateObject("Scripting.Dictionary") For i = 2 To 7 myDic(Cells(i, 1).Value) = Cells(i, 2).Value Next i myAr() = myDic.Keys MsgBox Join(myAr()) End Sub 上記2つのマクロは、Keyに関してはまったく同じ働きをするようです。 ところがItemに関しては、Keyが重複した場合、あとから出てきた方に上書きされるようです。 これはtest01では、Keyの重複を排除しているためItemは最初に出たものが残る、test02は重複の場合、無条件でKeyが上書きされ(ても値は変化しないけど)、したがってItemも上書きされるという理解でよろしいのでしょうか? ならば、Itemを気にしない場合、わざわざ If Not myDic.exists(Cells(i, 1).Value) Then myDic.Add Cells(i, 1).Value, Cells(i, 2).Value End If と、3行も費やして重複のチェックをしなくとも myDic(Cells(i, 1).Value) = Cells(i, 2).Value のわずか一行で済むということですよね?

  • エクセルでDictionaryオブジェクト

    メリークリスマス! とはいうものの仕事が終わりません。 これまでエクセルでDictionaryオブジェクトを利用し、AN列にある人名データをKeyにしてT列にある金額の集計を行っていました。 条件 AN列のデータには重複するものが多いが同姓同名は存在しない。 T列には必ず数値が入力されている。 AN列にある人名ごとにT列にある金額の集計を行う。 省略してますが以下のようなコードです。 Sub test01()   Dim myDic As Object   Dim x As Long   Dim myC As Range   Dim ws As Worksheet   Set myDic = CreateObject("Scripting.Dictionary")   x = Cells(Rows.Count, "AN").End(xlUp).Row   For Each myC In Range("AN1:AN" & x) '受取人名列     If Not myDic.Exists(myC.Value) Then       myDic.Add myC.Value, Cells(myC.Row, "T").Value 'T列の金額     Else       myDic(myC.Value) = myDic(myC.Value) + Cells(myC.Row, "T").Value '金額を加算     End If   Next   Set ws = Worksheets.Add(After:=ActiveSheet)   With ws '新規ワークシート     .Range("A1").Resize(myDic.Count, 1).Value = Application.Transpose(myDic.keys) 'A列にデータ     .Range("B1").Resize(myDic.Count, 1).Value = Application.Transpose(myDic.Items) 'B列に結びつけ金額データ   End With   Set myDic = Nothing End Sub これでうまくできていたのですが、今回新しい条件が加わり、頭を悩ませております。 新たな条件とは、同じ表のN列にあるコード(数字8桁)のうち、例えば77777777のものがあれば、追加したワークシートのC列にフラグをたてるというものです。 どのようにすればできるでしょうか? よろしくお願いいたします。

  • Excelマクロ

    お世話になります。 Excelマクロについて、ざっくりとした質問なのですが、 以下のマクロを実行した時に、オブジェクトXXXには、 どのようなものを格納できるのでしょうか。 Dim XXX As Object Set XXX = CreateObject("Scripting.Dictionary") 「CreateObject」と「Scripting.Dictionary」の使い方を調べてはみたのですが、 それぞれの使い方が今ひとつ分かりません。 お力添えいただきたいと思います。 よろしくお願いいたします。 以上

  • 以下のデータがあり、これをExcel VBAの連想配列として格納したい

    以下のデータがあり、これをExcel VBAの連想配列として格納したいと考えています。 MsgBoxでキーとアイテムを表示させると表示されるのですが、 最後に一例としてExistsで確認するとFalseが返ってきます。 これは配列に格納されていないのでしょうか。 また格納されていないとすると、どうすれば格納できるのでしょうか。 A 列   B列 35   apple 37   orange 40   banana 以下がコードです。 sub test() Dim i as integer Dim myDic as Object Dim keys as Variant Set myDic = CreateObject("Scripting.Dictionary") For i = 1 to 3 myDic.Add Cells(i, 1), Cells(i, 2) Next i keys = myDic.keys For Each keys In myDic MsgBox "キー名:" & keys & vbCr & "値:" & myDic.Item(keys) Next keys MsgBox myDic.Exists(35) End Sub

  • Excelで文字を置換したいのですが

    A列の各セルに入っている文字列において、Bという文字があったらCに、無かったら文字を削除して空白にする、という作業を行いたいのです。 行数にして700行くらいありますので、マクロを考えました。 Replaceメソッドを使うのだと思い、ネットの記事を参考に、以下のマクロを書いてみましたが、「含まない」が機能しません。 「Bを含まない場合は削除する」というのはどのようにしたら良いでしょうか。 Sub macro9() 'Dictionaryオブジェクトの宣言 Dim myDic As Object Set myDic = CreateObject("Scripting.Dictionary") 'Dictionaryオブジェクトの初期化、要素の追加 myDic.Add "*B", "C" myDic.Add "<>B", "" 'Dictionaryオブジェクトを使った複数条件の置換 Dim bool As Boolean, myRange As Range Set myRange = Range("A3:A700") For Each Var In myDic bool = myRange.Replace(Var, myDic(Var)) Next Var End Sub

  • VBA DictionaryオブジェクトのItemについての質問です。

    エクセル2000です。 A列からE列までの1行から最終行不特定の表があります。 A列はすべて文字列で、B~Gは数値、E列は文字列です。 A列の文字列には重複があります。 この表を別シートにA列の重複がない表として作成したいと思います。 その際、列が重複する場合にはB~G列は合計数値、E列は文字列を結合させます。 Dictionaryオブジェクトを用い、A列データをKey、B~E列データを配列でItemとして下記のコードを書きました。 このコードで目的は達成しました。 質問はKeyが重複する場合、B~E列のデータを配列として取り込んだItemに次のB~E列のデータを加算あるいは結合する方法の簡略化です。 このコードではItem内の配列データを、さらに配列変数のmyArに代入して、要素ごとにForNextで回しましたが、配列変数にわざわざ代入しなくとも出来る方法があるかどうかが知りたいのです。 あるいはまったく別な方法でもかまいません。 ご教示いただければ幸いです。 Sub ItemsTest() Dim myDic As Object, ns As Worksheet '変数宣言 Dim c As Range, cc As Range, i As Integer Dim myAr Set myDic = CreateObject("Scripting.Dictionary") 'myDicを用意 For Each c In Range(Cells(1, "A"), Cells(Rows.Count, "A").End(xlUp)) 'A列の各データについて If Not myDic.exists(c.Value) Then 'myDicになければ myDic.Add c.Value, Array(c.Offset(0, 1).Value, c.Offset(0, 2).Value, c.Offset(0, 3).Value, c.Offset(0, 4).Value) '追加しB~E列データを配列でItemに Else 'myDicにあれば myAr = myDic(c.Value) 'Itemを配列myArに For i = LBound(myAr) To UBound(myAr) myAr(i) = myAr(i) + c.Offset(0, i + 1).Value '配列の要素ごとに加算 Next i myDic(c.Value) = myAr '配列myArをItemにもどす End If Next c '繰り返し Set ns = Worksheets.Add(After:=ActiveSheet) 'シートを追加 ns.Range("A1").Resize(myDic.Count, 1).Value = Application.Transpose(myDic.Keys) 'A列にKeyデータ転記 For Each cc In ns.Range("A1:A" & myDic.Count) cc.Offset(0, 1).Resize(, UBound(myAr) + 1).Value = myDic.Item(cc.Value) 'B~E列にItemデータ転記 Next End Sub  (o。_。)oペコッ

  • エクセルVBAでDictionaryオブジェクトについて

    エクセル2000です。 例えばA列に国名、B列に都市名、C列に団体名が切れ目なく並ぶリストがあります。 表はA列を基準にソートされています。 A列の同じ国名が終わる行のD列の1個のセルに、そこまでのC列で出てきた団体名を重複しないでカンマ区切りで表示しようと思います。 そのため、下記のようにDictionaryオブジェクトで団体名の重複を防いでいます。 Sub Test2() Dim i As Long Dim myStr As String Dim myDic Set myDic = CreateObject("Scripting.Dictionary") For i = 2 To Cells(Rows.Count, "A").End(xlUp).Row If myDic.exists(Cells(i, "C").Value) = False Then myStr = myStr & Cells(i, "C").Value & "、" myDic.Add Cells(i, "C").Value, "" End If If Cells(i, "A") <> Cells(i + 1, "A") Then Cells(i, "D") = Left(myStr, Len(myStr) - 1) myStr = "" End If Next i End Sub 問題は、国をまたいで同じ団体名が出てきた場合、すでに上の方の国で変数myDicに登録されているため、登録されないということです。 上記コードでD列に変数myStを転記し、myStrを = ""にした時に、変数myDicの方もクリアしてしまえばいいとは思うのですが、どうやってクリアしたらよいのかわかりません。 ご教示くださいませ。 こんな感じにしたいのです。 日本 東京 abc 日本 横浜 bbc 日本 大阪 bbc 日本 名古屋 abc 日本 札幌 abc bbc、abc 韓国 ソウル kbc 韓国 プサン kkc 韓国 テグ kbc 韓国 テジョン abc 韓国 インチョン bbc kbc、kkc、bbc、abc 北朝鮮 ピョンヤン xxc 北朝鮮 テポドン xxc xxc 中国 北京 ccc 中国 南京 ccc 中国 上海 abc 中国 大連 kbc ccc、abc、kbc 表が上手く表示されませんが、各国名の最終行のB列都市名の右の1個はC列の団体名で、その右にくっついて見えるのがD列のカンマ区切りのデータです。

  • VBAのdictionaryでAddの使い方

    VBAでつぎのコードを実行すると、a,A1.1の後、a,A2.2と表示します。 dicには、a,A2.2の設定をしていないのになぜこうなるのでしょうか? どなたか教えてください。 Sub sample() Dim dic As Object Dim subDic As Object Set dic = CreateObject("Scripting.Dictionary") Set subDic = CreateObject("Scripting.Dictionary") subDic.Add "A1", 1 dic.Add "a", subDic subDic.Add "A2", 2 '結果表示 Dim key1 As Variant Dim key2 As Variant For Each key1 In dic.keys For Each key2 In dic(key1).keys MsgBox key1 & "," & key2 & ". " & dic(key1)(key2) Next Next End Sub

  • エクセルVBAで重複入力の排除

    すでに入力規則はリストで使用しております。 そのためVBAで重複入力の排除を行おうと思います。 一応以下のコードでできたのですが、もっと良い方法があったら教えてください。 お願いいたします。 Private Sub Worksheet_Change(ByVal Target As Range)    Dim myDic As Object    Dim c As Variant, varData As Variant    Dim i As Long    If Application.Intersect(Target, Range("A1:A50")) Is Nothing Then Exit Sub    Set myDic = CreateObject("Scripting.Dictionary")    varData = Range("A1:A50").Value    For Each c In varData      If Not c = Empty Then        i = i + 1        If Not myDic.Exists(c) Then          myDic.Add c, Null        End If      End If    Next    If myDic.Count < i Then     MsgBox Target & " は重複!"     Application.EnableEvents = False     Application.Undo     Application.EnableEvents = True    End If End Sub

  • PHPのようにスマートに配列の配列など記述する方法が

    PHPの場合、データ構造ですが以下のようになっています。 $a = array( "test1" => array( array(1,1), array("x", 2) ), "test2" => array( array(3,2), array("y", 1) ), ); これをエクセルVBAの場合、Scripting.Dictionaryを使えば連想配列が 可能ですが、PHPのようにスマートに配列の配列など記述する方法が わかりません。 Dim dic As Scripting.Dictionary set dic = New Scripting.dictionary dic.Add "test1", ???????????????? dic.Add "test2", ???????????????? スマートにデータ構造を実現できる方法が知りたいです。

専門家に質問してみよう