重要なお知らせ

「教えて! goo」は2025年9月17日(水)をもちまして、サービスを終了いたします。詳細はこちら>

【GOLF me!】初月無料お試し

いつもお世話になっております
以前、某氏から頂戴しましたコードです。
下記の部分がイマイチまかりません。
あとはなんとかわかりました。
詳しくおしえてくれませんでしょうか

dicT(key) = pix
ix = pix
pix = pix + 1


Sub 集計()
Dim dicT As Object
Dim maxrow As Long
Dim wrow As Long
Dim wcol As Long
Const max_person As Long = 1000 '最大人数
Dim price(max_person, 12) As Long '金額
Dim count(max_person, 12) As Long '件数
Dim pix As Long 'price&countへのindex
Dim ix As Long 'price&countへのindex
Dim key As Variant
Dim mm As Long
Dim cx As Long
pix = 1
Set dicT = CreateObject("Scripting.Dictionary") ' 連想配列の定義
maxrow = Cells(Rows.count, 1).End(xlUp).Row '1列目の最終行を求める
For wrow = 2 To maxrow
key = Cells(wrow, "D").Value
If dicT.exists(key) = True Then
ix = dicT(key)
Else
dicT(key) = pix
ix = pix
pix = pix + 1
End If
mm = Month(Cells(wrow, "A").Value) '月を算出
price(ix, mm) = price(ix, mm) + Cells(wrow, "E").Value '金額加算
count(ix, mm) = count(ix, mm) + 1 '件数加算
Next
wrow = 3

For Each key In dicT
ix = dicT(key)
Cells(wrow, "G").Value = key '①追加

For mm = 1 To 12
cx = mm - 4

If cx < 0 Then cx = cx + 12
wcol = 8 + 2 * cx

Cells(wrow, wcol).Value = count(ix, mm) '件数設定
Cells(wrow, wcol + 1).Value = price(ix, mm) '金額設定
Next

wrow = wrow + 1
Next
End Sub

A 回答 (3件)

なんか珍しい部分で悩まれているみたいですね。



個人的には、

key = Cells(wrow, "D").Value
If dicT.exists(key) = True Then
ix = dicT(key)
Else
dicT(key) = pix
ix = pix
pix = pix + 1
End If
★(ここは抜いて)mm = Month(Cells(wrow, "A").Value) '月を算出
price(ix, mm) = price(ix, mm) + Cells(wrow, "E").Value '金額加算
count(ix, mm) = count(ix, mm) + 1 '件数加算

これで1固まりとして考えると答えがでる感じですけどね。

変数:ix は2つの二次元配列の行を指していると思って下さい。
それで、

key = Cells(wrow, "D").Value
If dicT.exists(key) = True Then
ix = dicT(key)

によりDictionaryオブジェクトのキーに変数:keyが既に存在していれば、格納しているアイテム(行番号)を ix に代入する。
存在していなければ(今回の質問)

dicT(key) = pix ' 行番号を変数:pixから取得する
ix = pix 'ここは単に ix に pix を代入して次の作業で使用する(別に ix = dicT(key) でも構わないと思いますよ?既に代入済みなので)
pix = pix + 1 '次回の為に行番号を新たに移動させる手段として +1 を加えておく

なんですけどね。

でもでも pix の初期値
pix = 1

pix = 0
であれば

pix = pix + 1 '行番号を新たに決定させる手段として +1 を加えておく
dicT(key) = pix ' 行番号を変数:pixから取得する
ix = pix 'ここは単に ix に pix を代入して次の作業で使用する(別に ix = dicT(key) でも構わないと思いますよ?既に代入済みなので)

とも書けたのですが。
    • good
    • 0
この回答へのお礼

なるほどです。
ありがとございました。

お礼日時:2019/07/13 21:33

'【つづき】



' 確認用データ作成

Public Sub testData()
  Dim vA As Variant
  Dim dt As Date
  Dim sS As String
  Dim i As Long, j As Long, n As Long

  Randomize

  sS = InputBox("何行?", , 10000)
  If (sS = "") Then Exit Sub
  n = Val(sS)
  If (n < 1) Then n = 1

  dt = DateSerial(Year(Date), 4, 1)
  ReDim vA(1 To n, 1 To 5)

  For i = 1 To n
    vA(i, 1) = Format(dt + Int(365 * Rnd()), "yyyy/m/d")
    vA(i, 2) = "B" & i
    vA(i, 3) = "C" & i
    sS = ""
    For j = 0 To Int(2 * Rnd())
      sS = sS & String(3, Chr(Asc("A") + Int(26 * Rnd())))
    Next
    vA(i, 4) = sS
    vA(i, 5) = (Int(999 * Rnd()) + 1) * 10
  Next

  With ActiveSheet
    .Cells.Delete
    With .Range("A2").Resize(n, 5)
      .Value = vA
      .EntireColumn.AutoFit
      If (MsgBox("Sort ?", vbYesNo) = vbYes) Then
        .Sort .Cells(4), xlAscending _
            , .Cells(1), , xlAscending, Header:=xlNo
      End If
    End With
    n = 8
    For j = 1 To 12
      With .Cells(1, n).Resize(, 2)
        .Merge
        .Value = IIf(j + 3 > 12, j - 9, j + 3)
        .HorizontalAlignment = xlCenter
      End With
      .Cells(2, n).Value = "件数"
      .Cells(2, n + 1).Value = "金額合計"
      n = n + 2
    Next
    .Columns.AutoFit
  End With
End Sub
    • good
    • 0
この回答へのお礼

いろいろ勉強になります。

お礼日時:2019/07/14 20:47

まだ閉じられていなかったので・・・



提示あった記述での Dictionary の使い方は、
配列変数 price count 其々の行、集計用に、誰に何行目を割り当てたか・・・ですね

Dictionary は、どれをキーにして、何を覚えさておく・・・・
自由に発想すれば良いと思います

例えば、

Samp1:提示あった記述と同じ、誰を何行目に割り当てたか

書き出し回数を減らしたいので、最終形のイメージに近い以下変数で
名前用配列 sA(1 To 1000, 1 To 1)
件数・金額合計のペアで 12 ヶ月分 jA(1 To 1000, 1 To 24)
値が出現しない部分を 0 埋めしたいので、jA は Long 型で
どの行に割り当てたかは、k = dic(vK) で入手
覚えていなかったら、キーが登録され、初期値の Empty が得られる
この時、k = 0 で判別できるように、各配列は 1 ~ としておく
集計後、配列 sA, jA を書き出して・・・

※ 配列を 静的に 1 ~ 1000 用意して
無駄だったり、足りなくなったり??
以下のように変更してみる???

Samp2:その人の集計する範囲を配列で覚えて、それを更新していく

配列のひな型 vA(0 To 24) で確保しておいて、集計部分 0 埋めしておく
v = dic(vK) して、覚えていたものを入手する
v が配列でなかったら、初めて出現した人(キー)
なら、v = vA して雛型をコピーして、名前を入れておく
更新したら、覚えなおして・・・・

覚えていた一人の 25 列分の配列を G 列から書き出せば、
ひとり分の書き出しは完了するけど、書き出し回数を減らしたい・・・
書き出す範囲は、With .Range("G3").Resize(dic.count, 25)
覚えていた値全体 dic.Items ・・・Transpose 2回すると、一気に書き出せる


※ 確認用データが必要なら、testData を実行すれば・・・

Dictionary は色々な使い方できるので、しっかり覚えておいた方が良いと思います


以前回答した以下

クロス集計
https://oshiete.goo.ne.jp/qa/10679533.html

この方法も理解しておくと、後々使えるかも?

dic : 行項目がキー ・・・ 値は Dictionary(2段目)
2段目キーは列項目 ・・・ 値は合計処理
dicM:列項目(上記2段目キー全部)

集計後、書き出し表分の配列を定義
ReDim vA(1 To dic.Count + 2, 1 To dicM.Count + 2)

列項目を2列目から展開しつつ、項目を何列目に書き出したか覚えておく
dic から覚えていたキーで
2段目キーから何列目への書き出しか dicM から求めて、その位置に集計値を
配列 vA を一気に書き出して、列・行 で並び替えて・・・



Option Explicit

Public Sub Samp1()
  Const CPC As Long = 1000 ' 最大人数
  Dim dic As Object
  Dim sA(1 To CPC, 1 To 1) As String
  Dim jA(1 To CPC, 1 To 24) As Long ' 件数、金額 x 12 組
  Dim vK As Variant
  Dim i As Long, j As Long, k As Long, n As Long, m As Long

  Set dic = CreateObject("Scripting.Dictionary")

  n = 0
  With ActiveSheet
    For i = 2 To .Cells(Rows.count, "A").End(xlUp).Row
      vK = .Cells(i, "D").Value
      m = Month(.Cells(i, "A").Value) - 4
      If (m < 0) Then m = m + 12
      j = m * 2 + 1
      k = dic(vK)
      If (k = 0) Then
        n = n + 1
        k = n
        dic(vK) = k
        sA(k, 1) = vK
      End If
      jA(k, j) = jA(k, j) + 1
      jA(k, j + 1) = jA(k, j + 1) + .Cells(i, "E").Value
    Next

    If (n > 0) Then
      Application.ScreenUpdating = False
      With .Range("G3").Resize(n, 25)
        .Columns(1).Value = sA
        .Columns(2).Resize(, 24).Value = jA
        .Sort .Cells(1), xlAscending, Header:=xlNo
      End With
      Application.ScreenUpdating = True
    End If
  End With

  Set dic = Nothing
End Sub


Public Sub Samp2()
  Dim dic As Object
  Dim wsf As WorksheetFunction
  Dim vA(0 To 24) As Variant
  Dim vK As Variant, v As Variant
  Dim i As Long, j As Long, m As Long

  Set dic = CreateObject("Scripting.Dictionary")
  Set wsf = WorksheetFunction

  For j = 1 To 24
    vA(j) = 0
  Next

  With ActiveSheet
    For i = 2 To .Cells(Rows.count, "A").End(xlUp).Row
      vK = .Cells(i, "D").Value
      m = Month(.Cells(i, "A").Value) - 4
      If (m < 0) Then m = m + 12
      j = m * 2 + 1
      v = dic(vK)
      If (Not IsArray(v)) Then
        v = vA
        v(0) = vK
      End If
      v(j) = v(j) + 1
      v(j + 1) = v(j + 1) + .Cells(i, "E").Value
      dic(vK) = v
    Next

    If (dic.count > 0) Then
      Application.ScreenUpdating = False
      With .Range("G3").Resize(dic.count, 25)
        .Value = wsf.Transpose(wsf.Transpose(dic.Items))
        .Sort .Cells(1), xlAscending, Header:=xlNo
      End With
      Application.ScreenUpdating = True
    End If
  End With

  Set dic = Nothing
  Set wsf = Nothing
End Sub

'【つづく】
    • good
    • 0
この回答へのお礼

いろいろためしました
有難うございます。

お礼日時:2019/07/14 20:46

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!