[[20220316161018]] 『VBAのDictionaryを使って、特定の文字があった場香x(VBA初心者ひば) ページの最後に飛ぶ

[ 初めての方へ | 一覧(最新更新順) | 全文検索 | 過去ログ ]

 

『VBAのDictionaryを使って、特定の文字があった場合にカウントしたい』(VBA初心者ひば)

countifを使用する場合のコードは理解できたのですが、
勉強中のDictionaryを使った場合のコードをネットで調べても、
よく理解出来なかったため質問します。

下記のようにA列の2行目から約70000行まで、
空欄または"あああ"が入っている行が混在しています。
A列に"あああ"と入っている行数を数えるVBAのコードを教えてください。
(下の場合は4とMsgboxに出るようにしたいです)

    A列
2行目 あああ
3行目 
4行目 あああ
5行目 あああ
6行目 



70000行目 あああ

< 使用 Excel:Office365、使用 OS:Windows10 >


 こんなので行けないかな?

 Sub Sample()
     Const strFixed As String = "あああ"
     Dim dicT As Object
     Dim aCell As Range

     Set dicT = CreateObject("Scripting.Dictionary")

     For Each aCell In Range("A2", Cells(Rows.Count, "A").End(xlUp))
         If aCell = strFixed Then
             dicT(strFixed) = dicT(strFixed) + 1
         End If
     Next

     MsgBox dicT(strFixed)
 End Sub

(半平太) 2022/03/16(水) 17:19


 蛇足ですが。

  複数候補について出現個数を集計する例にすると、
 Dictionaryを使う有難みがより明確になるかもしれません。
 (まあ、それ言い出したら、COUNTIFじゃないか等々、収拾がつかなくなります。
   マクロの練習という意味で考えます)

 Sub test()
     Dim dic As Object
     Dim r As Range
     Dim v As Variant

     Set dic = CreateObject("Scripting.Dictionary")
     dic("aa") = 0    '一例です。要修正
     dic("bb") = 0        

     For Each r In Range("A1", Cells(Rows.Count, "A").End(xlUp))
         v = r.Value
         If dic.Exists(v) Then
             dic(v) = dic(v) + 1
         End If
     Next
     [D1].Resize(dic.Count, 1) = Application.Transpose(dic.keys)
     [E1].Resize(dic.Count, 1) = Application.Transpose(dic.items)
 End Sub

 なお、数値(1)と数字("1")を同一視したい場合は、
 vを文字列型変数にするとよいと思います。

(γ) 2022/03/16(水) 20:01


便乗させていただき恐縮ですが。
Dictionaryの使い方が分かりやすくて大変勉強になりました。

例えばA列の飛び飛びセルに、あああ いいい あああ ううう ううう おおお あああ
とあるとして、重複を除いた数(この場合なら、4)を出したい場合も半平太様のDictionaryのやり方で出来たりしますか?
それとも違うやり方になりますか?
(便乗) 2022/03/19(土) 09:09


 当初の質問は「あああ」が何個あるかです。

 「あああ」限定なんて、Dictionaryの使い方としては極めて稀です。
  Dictionaryの出番さえないケースです。

 普通は、「あああ」「いい」・・がそれぞれ何個あるかを知りたい、なんて時でしょう。

 さて、便乗質問に関しては、「あああ」「いい」・・の種類の数ですから、
 それよりずーっと簡単で、Dictionaryのプリミティブな使い方と言えますね。

  Sub Sample()
      Dim dicT As Object
      Dim aCell As Range

      Set dicT = CreateObject("Scripting.Dictionary")

      For Each aCell In Range("A2", Cells(Rows.Count, "A").End(xlUp))
          If aCell <> "" Then
              dicT(aCell.Value) = Empty '「.Value」は省略してはならない
          End If
      Next

      MsgBox dicT.Count
  End Sub

(半平太) 2022/03/19(土) 09:53


半平太様、ありがとうございます!!
ご丁寧なご解説のお陰で、今まで使い方がよく分からず苦手意識のあったdictionaryが
身近でも使えそうな気になってきました。

Emptyを格納するとはどう言う事なのかが調べても分からず、、
すみません、教えて下さい。
(便乗) 2022/03/19(土) 12:30


 >Emptyを格納するとはどう言う事なのかが調べても分からず、

 Emptyに限定した話ではありません。
 "A"でもいいし、100でもいいです。何だっていいんです。

 目的は、重複のない(当然ですけど)キーが幾つあるかを調べることであって、
 対応するItemが何かは無関係です。

 そう言う場合、便乗さんは何を格納させますか?(彼女の名前?)

(半平太) 2022/03/19(土) 12:58


おぉ、そういう使い方(意味)でしたか。
理解しました。ありがとうございました!!
彼氏の名前でも入れておこうと思います(笑)
(便乗) 2022/03/19(土) 13:26

 すでにコメントいただいたとおりですが、
 つらつら書いてしまったので。

(1)

 重複を排除した要素の種類だけを得たいといった場合は、
 Emptyを itemに明示的にセットすることで、
 値は使わずKeyのほうにだけ興味があることを、
 コードを読む人(他人もしくは将来の自分)に明示的に示せます。

 また値を使う場合でも、
 そもそもEmptyとは、
    ・文字列としては""と同等、
    ・数値としては0と同等になる
 特別のキーワードなので汎用性はあります。

 ただし、個数をカウントしたい、などという場合は、
 dic("a") = 0
 などとすると意図は明確になると思います。

(2)

 一般的な話として、テキストではdic.Addを使う例が多いですが、
 実務的にはdic("A") = "B"といった書き方をすることが多いです。

 そして、本来Existsを使わないといけない場面で、
 If dic("A") = "" Then
 のように、(キーを作っていないのに)値を取得しようとすると、
 その行為によってkeyを"A"としたdictionaryのペアが作成されてしまうので、
 注意が必要です。

 以下を試してみます。
 Sub test()
    Dim dic As Object
    Set dic = CreateObject("Scripting.Dictionary")

    If dic("a") = 0 Then Debug.Print "間違った使い方"
    Debug.Print dic("a"), TypeName(dic("a"))    '(*)
 End Sub
 などとすると、(*)はエラーにならず、dic("a")が参照できてしまうことがわかります。

 その際、TypeNameは Emptyを返すので、
  ・itemは初期化されていないと解釈するのか、
  ・Empty値が自動的にセットされているとみるか
 は自信がありませんが、明示的にEmptyとしていないので、
 たぶん前者の解釈になるのかなとは思いますが。

(γ) 2022/03/19(土) 14:11


γ様
大変参考になるご解説、ありがとうございます。
奥深いですね。dictionaryを使いこなせるように頑張ってみます。
3/16のγ様のご投稿も併せて、実践してみて大変勉強になりました。
ありがとうございました!
(便乗) 2022/03/19(土) 17:14

コメント返信:

[ 一覧(最新更新順) ]


YukiWiki 1.6.7 Copyright (C) 2000,2001 by Hiroshi Yuki. Modified by kazu.