• ベストアンサー
※ ChatGPTを利用し、要約された質問です(原文:Dictionaryのitemを効率よく配列に格納)

Excel VBAでDictionaryを使用して商品別の売上高一覧を作成する方法

このQ&Aのポイント
  • Excel VBAのDictionaryオブジェクトを使用して、商品別の売上高一覧を作成する方法について説明します。
  • 質問者のマクロでは、Dictionaryオブジェクトを使って商品名と分類名をキーとして売上高を管理し、一覧データを配列に格納しています。
  • しかし、質問者は要素の個数が大きくなるとTransponse関数の制限にひっかかる可能性があることに懸念を抱いています。どのような方法で効率的に処理できるか教示を求めています。

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

  • ベストアンサー
  • end-u
  • ベストアンサー率79% (496/625)
回答No.1

A)ダイレクトにitemsをFor Eachで回すか Dim d i = 0 For Each d In dic.Items   i = i + 1   Debug.Print i, d Next B)ダイレクトにitemsをIndexで回すか Dim i As Long For i = 0 To dic.Count - 1   Debug.Print i + 1, dic.Items()(i) Next C)Transpose関数制限回避のFunctionを作っておくか http://okwave.jp/qa/q5031943.html D)そもそもitemに格納せずに最初から書き出し用配列で加算するか Dim s As String For i = 1 To UBound(myV)   s = myV(i, 1) & myV(i, 2)   If Not myDic.Exists(s) Then '商品+分類が初出なら     n = n + 1 'カウント(配列のIndex)     '(この時itemにはカウントアップした配列Indexを格納します)     myDic.Add s, n 'keyに追加、itemにIndex     myW(n, 1) = myV(i, 1) '配列に商品名     myW(n, 2) = myV(i, 2) '配列に分類名     myW(n, 3) = myV(i, 3) '配列に売上   Else '商品+分類が既出なら     myW(myDic(s), 3) = myW(myDic(s), 3) + myV(i, 3) '配列に売上加算   End If Next i ..など。 今回、速度的なものは検証してません。 いろいろ試してみてください。

merlionXX
質問者

お礼

end-uさま、いつもありがとうございます。 いろんな方法がありますね、自分の未熟さを痛感します。 (///▽///) 5万3千行の同一データで試しました。 1回目 test01(掲示したわたしのコード) 0.515625  test02(最初から書き出し用配列で加算) 0.390625  test03(itemsをFor Eachで回す) 0.515625 test04(itemsをIndexで回す) 0.546875 test05(Transpose回避Function) 0.53125   2回目 test01 0.53125 test02 0.390625 test03 0.53125 test04 0.53125 test05 0.53125 3回目 test01 0.515625 test02 0.375 test03 0.53125 test04 0.515625 test05 0.53125 という結果でした。 最初から書き出し用配列で加算がNo1で、あとは大差なしというところです。 せっかくDictionaryオブジェクトを使うんだからItemで加算と考えていましたが、最初から配列に加算させた方が圧倒的に高速ですね。 もっともコンマ以下の差ですから、あとはコードの可読性も考えなければいけないのでしょうが。 大変勉強になりました。 ありがとうございます。(o。_。)o

merlionXX
質問者

補足

end-uさま、その後もテストを続けた結果、まったく異なる事実に気づきました。 お礼で、test02(最初から書き出し用配列で加算) が最速と書きましたが、test02とその他の記述の違いに気づきました。 test02では、s = myV(i, 1) & myV(i, 2) と、商品名と分類をまとめて変数に代入したコードですが、他はmyV(i, 1) & myV(i, 2) のまま使用しています。 ひょっとしてと思い、test01、test03~test05もすべてs = myV(i, 1) & myV(i, 2) と、変数方式に変えて比較しました。 結果は以下の通り test01(掲示したわたしのコード) 0.375 test02(最初から書き出し用配列で加算) 0.390625  test03(itemsをFor Eachで回す) 0.375 test04(itemsをIndexで回す) 0.375 test05(Transpose回避Function) 0.390625 逆に、初から書き出し用配列で加算だけが変わりませんので、もっとも遅いという結果になりました! 変数に入れることでこんなに変わるなんて驚きです。 すっごく勉強になりました。

すると、全ての回答が全文表示されます。

その他の回答 (1)

  • end-u
  • ベストアンサー率79% (496/625)
回答No.2

データ型に応じて、配列の型を適切に決める事が可能なら もう少し改善できるかと思います。 Sub try()   Dim dic As Object 'Scripting.Dictionary   Dim s  As String   Dim i  As Long   Dim j  As Long   Dim n  As Long   Dim mx As Long   Dim v  As Variant   Dim w() As String   Dim x() As Long 'Double   With Sheets("Sheet1")     v = .Range("A1", .Cells(.Rows.Count, "C").End(xlUp)).Value   End With   mx = UBound(v)   ReDim w(1 To mx, 1 To 2)   ReDim x(1 To mx, 1 To 1)   Set dic = CreateObject("Scripting.Dictionary") 'New Dictionary   For i = 1 To mx     s = v(i, 1) & v(i, 2)     If Not dic.Exists(s) Then       n = n + 1       dic(s) = n       w(n, 1) = v(i, 1)       w(n, 2) = v(i, 2)     End If     j = dic(s)     x(j, 1) = x(j, 1) + v(i, 3)   Next   With Sheets.Add     .Range("A1:B1").Resize(n).Value = w     .Range("C1").Resize(n).Value = x   End With      Erase w, x   Set dic = Nothing End Sub #当然、[Microsoft Scripting Runtime]を参照設定すればもっと速くなりますが。

merlionXX
質問者

お礼

重ね重ねありがとうございます。 > 当然、[Microsoft Scripting Runtime]を参照設定すればもっと速くなりますが。 やってみました。 自宅なので昨日と同じデータでは試せないのですが、5万行のテストデータを作成して他のコードと比較をしてみたら、なんと半分の時間でした。 すごいですねえ。

すると、全ての回答が全文表示されます。

関連するQ&A