途中まで出来ているのですが‥(Dicへの複数item追加?)
A B C D E ←シート元
1 大区分 中区分 金額1 金額2 小区分 ←見出し行です。
2 A社 管理課 12000 3000 1
3 B社 総務課 10000 2000 1
4 C社 業務課 800 1000 3
5 A社 総務課 5
6 C社 製造課 600 5000 2
7 A社 製造課 15000 1
8 A社 管理課 300 1
9 B社 管理課 800 2000 4
10 D社 総務課 90000 9000 1
を大区分 中区分 小区分をKeyにして3要素が同じものをまとめて並び替えて集計するのですが(下記のように 金額1 金額2ごとに足し算)
A B C D E ←シート集計
1 大区分 中区分 小区分金額1 金額2 ←見出し位置変更
2 A社 管理課 1 12000 3300
3 A社 総務課 5
4 A社 製造課 1 15000
5 B社 総務課 1 10000 2000
6 B社 管理課 4 8000 2000
以下省略
実際に作りたいものは、元シートの金額の項目が多いのです(列が飛び飛びに40位あります)今回の例でいえばCとDが CからF HからV ABからCHとなりそれぞれ金額3,4,5~50みたいになってます。私なりに下記のコードのように進めてますが、表題のようにDictionaryに複数のitemを追加する方法が解らないため、金額の項目ごとに算出を繰り返すという効率が悪い方法をとってます。どなたかご教示頂けると幸いです。
Sub 3keyと2要素()
’実際は40要素くらいある
Dim OLDBOOK As Workbook
Dim SH1 As Worksheet
Dim SH2 As Worksheet
Dim myDic As Object, myKey, myItem
Dim myVal, myVal2, myVal3, myVal4, myVal5
Dim i As Long
Set OLDBOOK = ThisWorkbook
Set SH1 = OLDBOOK.Worksheets("元")
Set SH2 = OLDBOOK.Worksheets("集計")
SH2.Cells.ClearContents
SH2.Range("A1:B1").Value = SH1.Range("A1:B1").Value
SH2.Range("C1").Value = SH1.Range("E1").Value
SH2.Range("D1:E1").Value = SH1.Range("C1:D1").Value
Set myDic = CreateObject("Scripting.Dictionary")
SH1.Select
myVal = SH1.Range("A2", Range("A" & Rows.Count).End(xlUp)).Resize(, 5).Value
For i = 1 To UBound(myVal, 1)
myVal2 = myVal(i, 1) & "_" & myVal(i, 2) & "_" & myVal(i, 5)
If Not myVal2 = "_" & "_" Then
If Not myDic.exists(myVal2) Then
myDic.Add myVal2, myVal(i, 3)
Else
myDic(myVal2) = myDic(myVal2) + myVal(i, 3)
End If
End If
Next
myKey = myDic.keys ' 書き出し とりあえず2要素
myItem = myDic.items
For i = 0 To UBound(myKey)
myVal3 = Split(myKey(i), "_")
SH2.Cells(i + 2, 1).Value = myVal3(0)
SH2.Cells(i + 2, 2).Value = myVal3(1)
SH2.Cells(i + 2, 3).Value = myVal3(2)
SH2.Cells(i + 2, 4).Value = myItem(i)
Next
Set myDic = Nothing
'********
Set myDic = CreateObject("Scripting.Dictionary")
myVal = SH1.Range("A2", Range("A" & Rows.Count).End(xlUp)).Resize(, 5).Value
For i = 1 To UBound(myVal, 1)
myVal2 = myVal(i, 1) & "_" & myVal(i, 2) & "_" & myVal(i, 5)
If Not myVal2 = "_" & "_" Then
If Not myDic.exists(myVal2) Then
myDic.Add myVal2, myVal(i, 4)
Else
myDic(myVal2) = myDic(myVal2) + myVal(i, 4)
End If
End If
Next
myKey = myDic.keys
myItem = myDic.items
For i = 0 To UBound(myKey)
myVal3 = Split(myKey(i), "_")
SH2.Cells(i + 2, 5).Value = myItem(i)
Next
Set myDic = Nothing
' 以下繰り返しするしかなく困ってます
SH2.Select
SH2.Range("A2", Range("E" & Rows.Count).End(xlUp)).Sort _
Key1:=Range("AF2"), Order1:=xlAscending, _
Key2:=Range("B"), Order2:=xlAscending, _
Key3:=Range("C2"), Order3:=xlAscending, _
Header:=xlGuess
Set OLDBOOK = Nothing
Set SH1 = Nothing
Set SH2 = Nothing
End Sub
お礼
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
補足
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 逆に、初から書き出し用配列で加算だけが変わりませんので、もっとも遅いという結果になりました! 変数に入れることでこんなに変わるなんて驚きです。 すっごく勉強になりました。