|    | 
     ▼ドカ さん: 
 
こんにちは 
ご理解いただけたようでなによりです。 
 
>UO3さんはどうやって、「子Dictionary」なるものが作れると知ることが出来たのでしょうか? 
 
う〜ん、なんとなくです? 
この例は、少なからず、掲示板などの回答としてでていますし、回答者さんの中には 
「自分が発見した!皆さんもどうぞ」なんてコメントする人もいます。 
その人は、本当に、ご自分で発見されたんでしょうし、同じく、私も発見? 
Dictionaryに限らず、私の場合は、できる、できないの前に、 
「こんなことができたらいいなぁ」とか「こんなふうにやるとできるべきなのになぁ」なんて考えます。 
(VBAだけじゃなく、エクセルの操作でも) 
で、やってみると、「おっ!できるじゃん」とか「あぁ、やっぱりだめだよね」 
最初は、たとえばユーザーフォーム上のコンロロールを配列的に扱うために、 
配列を用意して、そこに「クラス」を登録することからはじめたような記憶があります。 
(この部分は、参考書に、よく記載されていますので) 
で、思考(?)の順序としては 
・クラスもオブジェクトだよね 
・じゃぁ、配列にその他のオブジェクトをいれられたら、便利かも。 
・で、やってみます。結果は「おっ!できるじゃん」です。 
・そのあと、Dictionaryの中身の実態も配列だよね。じゃぁ、その中身にDictionaryというオブジェクトを 
 いれることができれば、そのキーごとの「子Dictionary」を保持することができるんじゃないかな? 
・で、やってみます。またまた結果は「おっ!できるじゃん」す。 
こんな経緯でしたね。 
 
私は手軽に扱えるので、もっぱら、この方法なんですが、本当のエキスパートさんになると 
Dictionaryのデータという「窮屈」な場所をつかうのではなく、私が言う、「子Dictionary」を 
「データ保持クラス」といった目的の「クラス」を生成して扱ってらっしゃいますね。 
このほうが、どんな形のデータももてますし、データ処理のためのコードすら持てます。 
 
>この記述ですが、本当なのでしょうか? 
 
まず、Dictionary は「かなり速い」ツールです。でも、圧倒的に一番かというと、まずますという 
ところなんだろうなと思います。「天才」ではなく「秀才」ですね。もちろん、「秀才」ですから 
「並の人」より、光り輝いているんです。 
 
たとえば、以下のサンプルは、きわめて単純なレイアウトをきわめて単純なロジックで扱った場合の 
比較です。ほとんど差はありませんが、「秒以下」のところで「ほんの少し」差がでます。 
これが、もっともっと複雑なレイアウトで複雑なマッチングロジックになると、極端な場合、 
Dictionary処理が1.5倍ぐらいかかるケースもありえます。 
 
・まず、DataGen を実行してください。 
 これは、結構時間がかかりますけど、がまんしてください。 
 Sheet1 のA列,B列に50,000行のランダムな値をセットします。 
 Test1,Test2を実行すると、Sheet1 がかわってしまいますので、比較を公平にするために 
 1つ実行したら、Sheet2 から セルの内容をSheet1 にコピペしてESCキーでリセットしてから 
 もう1つを実行してください。 
 
Sub TestGen() 
  Dim i As Long 
  Dim x As Long 
  Dim z As Long 
   
  With Sheets("Sheet1") 
    .Cells.Clear 
    For i = 1 To 50000 
      x = Int((1000) * Rnd + 1) 
      z = Int((100) * Rnd + 1) 
      .Cells(i, "A").Value = "A" & Format(x, "0000") 
      .Cells(i, "B").Value = z 
    Next 
    .Cells.Copy Sheets("Sheet2").Range("A1") 
  End With 
   
End Sub 
 
Sub Test1() 
  Dim dic As Object 
  Dim c As Range 
  Dim myTime As Double 
   
  myTime = Timer   '計測開始 
   
  Application.ScreenUpdating = False 
  Set dic = CreateObject("Scripting.Dictionary") 
   
  With Sheets("Sheet1") 
    With .Range("A1", .Range("A" & .Rows.Count).End(xlUp)) 
      For Each c In .Cells 
        If c.Value > dic(c.Value) Then dic(c.Value) = c.Offset(, 1).Value 
      Next 
    End With 
    .Columns("C:D").Clear 
    .Range("C1").Resize(dic.Count).Value = WorksheetFunction.Transpose(dic.keys) 
    .Range("D1").Resize(dic.Count).Value = WorksheetFunction.Transpose(dic.items) 
  End With 
  Application.ScreenUpdating = True 
   
  MsgBox Timer - myTime 
   
End Sub 
 
Sub Test2() 
  Dim dic As Object 
  Dim c As Range 
  Dim myTime As Double 
  Dim v() As Variant 
  Dim k As Long 
  Dim oldkey As Variant 
  Dim maxNum As Long 
   
  myTime = Timer   '計測開始 
   
  Application.ScreenUpdating = False 
   
  With Sheets("Sheet1") 
    With .Range("A1", .Range("A" & .Rows.Count).End(xlUp)) 
      .Resize(, 2).Sort key1:=.Range("A1"), order1:=xlAscending 
      ReDim v(1 To .Rows.Count, 1 To 2) 
      For Each c In .Cells 
        If c.Value <> oldkey Then 
          k = k + 1 
          maxNum = 0 
        End If 
        If c.Offset(, 1).Value > maxNum Then maxNum = c.Offset(, 1).Value 
        oldkey = c.Value 
        v(k, 1) = oldkey 
        v(k, 2) = maxNum 
      Next 
    End With 
    .Columns("C:D").Clear 
    .Range("C1").Resize(k, 2).Value = v 
  End With 
  Application.ScreenUpdating = True 
   
  MsgBox Timer - myTime 
 
End Sub 
 
 | 
     
    
   |