Sub mondai6()
Dim sp() As String
Dim cYk As Long
Dim cTt As Long
Dim slist() As Variant
Dim c As Long
Dim m As Long
c = 0
Dim st As String
For cTt = 0 To 97
sp = Split(Range("A2").Offset(cTt).Value, ",")
For cYk = LBound(sp) To UBound(sp)
ReDim Preserve slist(1, c)
'一番最初は、配列に即登録
If c = 0 Then
slist(0, c) = sp(cYk)
slist(1, c) = 1
c = c + 1
'2回目以降はFunctionで存在を判定
Else
st = sp(cYk)
If isExists(slist, st) = False Then
'名前が存在しなかったので、登録
slist(0, c) = sp(cYk)
slist(1, c) = 1
c = c + 1
Else
'名前が存在。配列から該当の名前のslist(1,m)を探し出し、1を足す。
For m = LBound(slist, 2) To UBound(slist, 2)
If st = slist(0, m) Then
slist(1, m) = slist(1, m) + 1
Exit For
End If
Next
End If
End If
Next
Next
'リストを書き出し
For c = LBound(slist, 2) To UBound(slist, 2)
Range("H2").Offset(c) = slist(0, c)
Range("I2").Offset(c) = slist(1, c)
Next
End Sub
Function isExists(slist() As Variant, st As String) As Boolean
Dim hantei As Boolean
Dim rg As Variant
hantei = False
For Each rg In slist
If st = rg Then
hantei = True
End If
Next
isExists = hantei
End Function
【質問】 ①d.keysの中身が文字であっても、配列の変数に代入する場合はVariant型で なければいけないということで良いでしょうか。 (試しに、String型の変数に代入しようとしたら、型が違うとエラーになりました。) Dim v As Variant v=d.keys
②動的配列や、静的配列の時は、配列の変数を宣言するときに、()をつけていましたがDictionaryの時はつけてもつけなくてもどちらでも良いのでしょうか。 ↓因みにこれでも動きました。 Dim v() As Variant v=d.keys でも、動的配列や静的配列の場合は、 Dim v (5) As Variant とか Dim v () As Variant Redim preserve v(c) ・・・*cはLong型の変数の意 の様に、()の中に数字を入れる必要がありますが、Dictionaryの場合は、 v=d.keys という感じになるので、()は書かない方が良いのかなと思いました。
'dictionaryのキーとしてオブジェクトを設定し、その後キーになっていたオブジェクトを削除する
Sub various_dic_keys_and_delete_key_object()
Worksheets.Add 'テストを容易にするため事前にシートを追加
Dim ws As Worksheet
Set ws = ActiveSheet
Dim dic As New Scripting.Dictionary
dic.Add ws, "sheet_value"
Range("A1").Value = dic.Count()
Range("B1").Value = dic.Item(ws) '出力される
ws.Delete
Range("A1").Value = dic.Count()
Range("B2").Value = dic.Item(ws) 'キーたるwsは存在しないのに、出力される
End Sub
2020/11/15 20:13
小川 慶一さんのコメント
(コメントID: 6938)
たかちゃんさん、田中 宏明さん:
すいません、最後のコード、少し直しました。以下のとおりです。 (元投稿も管理者権限にて修正済)
'dictionaryのキーとしてオブジェクトを設定し、その後キーになっていたオブジェクトを削除する
Sub various_dic_keys_and_delete_key_object()
Worksheets.Add 'テストを容易にするため事前にシートを追加
Dim ws As Worksheet
Set ws = ActiveSheet
Dim dic As New Scripting.Dictionary
dic.Add ws, "sheet_value"
Range("A1").Value = dic.Count()
Range("B1").Value = dic.Item(ws) '出力される
ws.Delete
Range("A1").Value = dic.Count()
Range("B2").Value = dic.Item(ws) 'キーたるwsは存在しないのに、出力される
End Sub
"can be anything except an array" ということで、配列はキーにできないようです。 以下は実行結果。
Sub dic_key_array_test()
Dim dic As New Scripting.Dictionary
Dim i As Integer
Dim i_array(3) As Integer
dic.Add i, "one"
dic.Add i_array, "two" 'ここでエラー
End Sub
'標準モジュール先頭で構造体を定義
Type point1
X As Integer
Y As Integer
End Type
Sub dic_key_Type_test()
Dim dic As New Scripting.Dictionary
Dim i As Integer
Dim i_Type As point1 '「構造体」(VBA標準)
i_Type.X = 1
i_Type.Y = 2
Dim j_Type As New point2 '構造体(クラスモジュール)
j_Type.X = 1
j_Type.Y = 2
dic.Add i, "one"
' 構造体(VBA標準)は、KeyもItemともに不可
' dic.Add i_Type, "two" 'ここでエラー
' dic.Add "two", i_Type 'これもエラー
' 構造体(クラスモジュール)は、KeyもItemともに可
dic.Add j_Type, "three"
dic.Add "three", j_Type
Debug.Print TypeName(dic.Keys(0)) 'Integer
Debug.Print TypeName(dic.Keys(1)) 'point2
Debug.Print TypeName(dic.Keys(2)) 'string
End Sub
'クラスモジュール point2 で構造体を定義
Public X As Integer
Public Y As Integer
> これは、仕様上の問題という気がします...。 > … > "can be anything except an array" ということで、配列はキーにできないようです。
たかちゃんさんの投稿
(投稿ID: 4924)
Dictionaryの代替プログラムを考える度に、Dictionaryの便利さが身に染みます。。。いつもありがとうございます。(><)
enshu1の問題6
小川 慶一さんのコメント
(コメントID: 6906)
僕が書いても概ねこんな感じになるかと思います。
> Dictionaryの便利さが身に染みます
まさに、ですね。
インデックスに数値以外のものを利用できるDictionaryのような配列は他の言語では当たり前にあります。
VBAはやはり配列関連の機能が弱いなぁ、と思わされるところです。
ひきつづき、スキルアップのプロセスをお楽しみください (^^
たかちゃんさんのコメント
(コメントID: 6907)
週末にも関わらず、チェックありがとうございました。
いつの日か、WindowsPCでDictionary使ってみたいです。(^^)
> たかちゃんさん:
>
> 僕が書いても概ねこんな感じになるかと思います。
>
田中 宏明さんのコメント
(コメントID: 6908)
二次元配列で連想配列を実現されるとは、すごいですね。
ダメ元でMac版でDictionaryを使う方法を試してみてはどうでしょうか。
https://forum.pc5bai.com/lesson/page/701?id=c12570
> いつの日か、WindowsPCでDictionary使ってみたいです。(^^)
たかちゃんさんのコメント
(コメントID: 6909)
こんばんわ。明日あたり一度試して見ます!
今日はたまたまワードを使う時があったのですが、開発タブにドロップダウンリストが出てこなくてメチャクチャ焦りました。(^^;;一応、リストはできたですが、フォームの保護がされていないと動きませんでした。
昔、Windowsでワードを使った時は、そんな使用になっていなかったと思うのですが、、、Mac版Officeはチョコチョコっと仕様が違う様で要注意です。(><)
> たかちゃんさん:
>
> 二次元配列で連想配列を実現されるとは、すごいですね。
>
> ダメ元でMac版でDictionaryを使う方法を試してみてはどうでしょうか。
> https://forum.pc5bai.com/lesson/page/701?id=c12570
>
> > いつの日か、WindowsPCでDictionary使ってみたいです。(^^)
田中 宏明さんのコメント
(コメントID: 6910)
投稿されたコードへのコメントです。
プロシージャに配列を受け渡しする際の基本を短期間でマスターされましてね。ハマったら以下を思い出してください。
・呼出側と受取側のデータ型が一致していること
・呼出側の()は省略可能で受取側の()は必須
たかちゃんさんのコメント
(コメントID: 6913)
ありがとうございます。呼び出し側に良く()つけてしましい、ハマりました。Dictionaryの件、教えて頂いた方法で動きました!
詳細は前の投稿にコメントしました。本当にありがとうございます。
一人だったら、とうの昔に諦めていました・・・。(^^;
暫く、この方法でDictionaryの勉強を続けて見ます!
> たかちゃんさん:
>
> 投稿されたコードへのコメントです。
> プロシージャに配列を受け渡しする際の基本を短期間でマスターされましてね。ハマったら以下を思い出してください。
> ・呼出側と受取側のデータ型が一致していること
> ・呼出側の()は省略可能で受取側の()は必須
小川 慶一さんのコメント
(コメントID: 6914)
以下に、ほかにもいろいろツールが公開されていますね。
https://github.com/VBA-tools
この方が主に開発されているよう。
https://github.com/timhall
> 田中さん:
> ありがとうございます。呼び出し側に良く()つけてしましい、ハマりました。Dictionaryの件、教えて頂いた方法で動きました!
> 詳細は前の投稿にコメントしました。本当にありがとうございます。
> 一人だったら、とうの昔に諦めていました・・・。(^^;
> 暫く、この方法でDictionaryの勉強を続けて見ます!
> > たかちゃんさん:
> >
> > 投稿されたコードへのコメントです。
> > プロシージャに配列を受け渡しする際の基本を短期間でマスターされましてね。ハマったら以下を思い出してください。
> > ・呼出側と受取側のデータ型が一致していること
> > ・呼出側の()は省略可能で受取側の()は必須
たかちゃんさんのコメント
(コメントID: 6916)
先生、ありがとうございます。GitHubについて調べて見たら、とても有名だと知りました。世の中には無償でこんな便利プログラムを提供してくださる方もいるんですね。先程、Dictionaryでもう少し込み入ったプログラムを書きましたが、便利すぎてびっくりしました。田中さんがDictionary大好きだとおっしゃっていた意味が、分かりました。(^^)
> たかちゃんさん:
>
> 以下に、ほかにもいろいろツールが公開されていますね。
> https://github.com/VBA-tools
>
> この方が主に開発されているよう。
> https://github.com/timhall
>
小川 慶一さんのコメント
(コメントID: 6920)
githubにはissueという項目があります。
コードに不具合と思しき挙動等があった場合の開発者とのやり取りのインターフェイスです。
このdictionaryライブラリについても、過去のやりとりが載っています。
おかしい挙動に出くわした場合は、こういうところでも情報収集してみてください。
https://github.com/VBA-tools/VBA-Dictionary/issues
たかちゃんさんのコメント
(コメントID: 6922)
ありがとうございます。お陰様で順調にDictionaryについて勉強できています。再確認と質問をさせてください。
【再確認したいこと】
Dictionaryの配列は、以下の2つがある。
.keysで、キーが1列に並んでいる配列が1つ。
.itemsで、値が1列に並んでいる配列が1つ。
文字が入っていても、数字が入っていても、配列の型はVariant型。
という認識で良いでしょうか。
【質問】
①d.keysの中身が文字であっても、配列の変数に代入する場合はVariant型で
なければいけないということで良いでしょうか。
(試しに、String型の変数に代入しようとしたら、型が違うとエラーになりました。)
Dim v As Variant
v=d.keys
②動的配列や、静的配列の時は、配列の変数を宣言するときに、()をつけていましたがDictionaryの時はつけてもつけなくてもどちらでも良いのでしょうか。
↓因みにこれでも動きました。
Dim v() As Variant
v=d.keys
でも、動的配列や静的配列の場合は、
Dim v (5) As Variant
とか
Dim v () As Variant
Redim preserve v(c) ・・・*cはLong型の変数の意
の様に、()の中に数字を入れる必要がありますが、Dictionaryの場合は、
v=d.keys という感じになるので、()は書かない方が良いのかなと思いました。
ーーー以上ここまでが、質問。以下、感想。
過去コメントのdic.item(文字列)、dic.items(数値)、dic.keys(数値)の違いの説明は
とても参考になりました。
> たかちゃんさん:
> githubにはissueという項目があります。
田中 宏明さんのコメント
(コメントID: 6924)
Dictionary大好き受講生が回答できそうな【質問】②について。
そもそもVariant型はどんなデータ型でも代入できる変数なので、Variant型配列も代入できてしまいます。
以下記事では、セル範囲をVariant型配列に入れる場合を例に、「Variant型()なし」と「Variant型配列()あり」の内部動作としてはの違いを考察されていますので参考にしてください。また、機能は同じであることが理解できると思います。
https://thom.hateblo.jp/entry/2015/08/30/141854
それから、DictionaryのKeysやItemsをわざわざVariant型配列に入れて処理するとひと手間増えるデメリットがありますが、データが大量になると、体感できるくらい処理が高速化されるメリットがあります。
> 【質問】
> ②動的配列や、静的配列の時は、配列の変数を宣言するときに、()をつけていましたがDictionaryの時はつけてもつけなくてもどちらでも良いのでしょうか。
たかちゃんさんのコメント
(コメントID: 6927)
おはようございます。ありがとうございます。そう言えば、Split関数の時も配列がそのままVariant型変数に入っていました。なるほど。
直接セルに書き出すのと、配列に値を格納してから書き出すのでこんなにも差があるんですね。教えて頂いたサイトのプログラム実行して見ましたが、4秒位差がありました。
私が質問した宣言時の()あり無しは、基本はどちらでないとダメってこともないんですね。内部がどうなるかだけ。
> それから、DictionaryのKeysやItemsをわざわざVariant型配列に入れて処理するとひと手間増えるデメリットがありますが、データが大量になると、体感できるくらい処理が高速化されるメリットがあります。
Enshu1の問題6を自分で書いていた時に、あんまり気にしないでd.keysを変数に格納しないで書いていました。試しに、教えて頂いたサイトの例からタイマーの部分のプログラムをコピペして計測してみました。
変数格納無し→0.09375
変数格納→0.078125
お話していた通り格納した方が早かったです!本当に良い話を聞きました。こんなちょっとした事に意味があったとは・・。いつもありがとうございます。(^^)
田中 宏明さんのコメント
(コメントID: 6929)
【質問】①について。
Split関数は、String型配列で定義した変数にも代入できました。
一方、Worksheetのセル範囲、DictionaryのKeysやItemsを一括代入する場合、String型配列で定義した変数に代入できず、Variant型配列を使用する必要があります。
その違いはよくわかりませんが、VBAの仕様と理解することで良いのではないでしょうか。
> 【質問】
> ①d.keysの中身が文字であっても、配列の変数に代入する場合はVariant型で
> なければいけないということで良いでしょうか。
> 田中さん
> おはようございます。ありがとうございます。そう言えば、Split関数の時も配列がそのままVariant型変数に入っていました。
たかちゃんさんのコメント
(コメントID: 6930)
調べて頂いてありがとうございます!出来ないから仕様なのかな・・と思いつつも自信がありませんでした。
> たかちゃんさん:
>
> 【質問】①について。
> Split関数は、String型配列で定義した変数にも代入できました。
> 一方、Worksheetのセル範囲、DictionaryのKeysやItemsを一括代入する場合、String型配列で定義した変数に代入できず、Variant型配列を使用する必要があります。
>
> その違いはよくわかりませんが、VBAの仕様と理解することで良いのではないでしょうか。
田中 宏明さんのコメント
(コメントID: 6931)
後で知ったのですが、過去に同様のやりとりがあったようです。
https://forum.pc5bai.com/lesson/page/701?id=c10350
> 田中さん:
> 調べて頂いてありがとうございます!出来ないから仕様なのかな・・と思いつつも自信がありませんでした。
小川 慶一さんのコメント
(コメントID: 6937)
【コメント1】
発展編1の第1章でお話したとおり、変数は、型を指定しないで宣言すると、暗示的に Variant型で生成されます。
Variant型なので、何でも投入できます。
数値、日付、文字列、セル、ワークシート...それらの配列...、そして、辞書も格納できます。
ただし、配列はサイズを指定しないと値の格納はできません。
また、サイズを指定すると、内部的に、Variant()になります。(*redim 時に型を指定するとその型の配列)
プロシージャ「hoge」、「omake」参照。
【コメント2】
Variant型はあとから配列にできますが、Variant型配列(つまり、 As Variant() で宣言したもの)はVariantとしては使えないので注意してください。
プロシージャ「set_value_for_var_array」参照。
【コメント3】
dictionaryのキーは、文字列以外も利用可能です。
プロシージャ「various_dic_keys」参照。
ということで、どうでしょうか。
質問への回答の代わりになっていそうな気がしますが。
> そもそもVariant型はどんなデータ型でも代入できる変数なので、Variant型配列も代入できてしまいます。
サンプル「various_dic_keys」で示したとおり、キーにオブジェクトを使えます。
しかし、言語としてそれは節操ないなという気がします。
たとえば、以下のように、dictionaryのキーとしてオブジェクトを設定し、その後キーになっていたオブジェクトを削除してみます。
このときなんと、辞書は、削除されたはずのシートをキーとして動作します。以下のとおり。
ウォッチ式で dicのキーを調べてみると、「変数なし」と表示されます。これは、仕様と言うにはちょっと心許ないです。
小川 慶一さんのコメント
(コメントID: 6938)
すいません、最後のコード、少し直しました。以下のとおりです。
(元投稿も管理者権限にて修正済)
田中 宏明さんのコメント
(コメントID: 6941)
なんとDictionaryのキーはオブジェクトも許容されているのですね。
過去、.Varue をつけ忘れてセル値をDictionaryのキーとするマクロが変な動きをした理由がよくわかりました。
いろいろ、ありがとうございます。
小川 慶一さんのコメント
(コメントID: 6943)
> なんとDictionaryのキーはオブジェクトも許容されているのですね。
これは、仕様上の問題という気がします...。
なお、公式を調べてみると、 "The key is used to retrieve an individual item and is usually an integer or a string, but can be anything except an array." とのこと。
https://docs.microsoft.com/ja-jp/previous-versions/windows/internet-explorer/ie-developer/windows-scripting/x4k5wbx4(v%3dvs.84)
"can be anything except an array" ということで、配列はキーにできないようです。
以下は実行結果。
田中 宏明さんのコメント
(コメントID: 6944)
本題から逸脱しますが、個人的興味で「構造体」を試してみました。
「構造体」は、キーやアイテムとして許容されませんでした。
クラスモジュールで定義した「構造体」は、キーもアイテムも許容されました。
> これは、仕様上の問題という気がします...。
> …
> "can be anything except an array" ということで、配列はキーにできないようです。
小川 慶一さんのコメント
(コメントID: 6946)
もはや謎仕様ですね (^^;