Dictionaryオブジェクトでキーが存在しているのに値が取得できない への返答
投稿で使用できる特殊コードの説明。(別タブで開きます。)
以下の返答は逆順(新しい順)に並んでいます。
投稿者 ヤマダ  (社会人)
投稿日時
2023/7/27 09:28:40
KOZさん
取り出すときの型まで考慮していませんでした。
キーをString型で登録することで、無事に思ったようにすることができました。
ありがとうございました。
取り出すときの型まで考慮していませんでした。
キーをString型で登録することで、無事に思ったようにすることができました。
ありがとうございました。
投稿者 魔界の仮面弁士  (社会人)
投稿日時
2023/7/26 18:18:24
> Set levelCd = CreateObject("Scripting.Dictionary")
CompareMode プロパティが未設定なので、キー比較は BinaryCompare モードのままですね。
> Dim test_csv() As level_Data
> test_csv.levelName = Worksheets("Sheet1").Cells(i, "A")
> test_csv.levelCd = levelCd.Item(keyChk)
これは文法的に不自然ではありませんか?
test_csv.levelName ではなく、
test_csv(i).levelName とかであればまだ分かりますが、
それにしたって ReDim 等が必要なはず…。
> 数値はキーとして設定できないのでしょうか?
いいえ、数値もキーにできます。
しかし、キーのデータ型がブレるのは、あまりお勧めしません。
キーは常に同じ型に揃えておいた方が無難です。
特に数値型や Empty が渡される可能性がある場合はなおのこと。
たとえば
Key:="KEY_" & Worksheets("Sheet1").Cells(i, "A").Value
のように、固定のプレフィックスなどを付けるとか、
Key:=CStr(Worksheets("Sheet1").Cells(i, "A").Value)
のように、キーを明示的に String 型に揃えておくなどです。
Excel の場合、未入力セルは Empty 値を返す点にも注意が必要です。
CompareMode プロパティが未設定なので、キー比較は BinaryCompare モードのままですね。
> Dim test_csv() As level_Data
> test_csv.levelName = Worksheets("Sheet1").Cells(i, "A")
> test_csv.levelCd = levelCd.Item(keyChk)
これは文法的に不自然ではありませんか?
test_csv.levelName ではなく、
test_csv(i).levelName とかであればまだ分かりますが、
それにしたって ReDim 等が必要なはず…。
> 数値はキーとして設定できないのでしょうか?
いいえ、数値もキーにできます。
しかし、キーのデータ型がブレるのは、あまりお勧めしません。
キーは常に同じ型に揃えておいた方が無難です。
特に数値型や Empty が渡される可能性がある場合はなおのこと。
たとえば
Key:="KEY_" & Worksheets("Sheet1").Cells(i, "A").Value
のように、固定のプレフィックスなどを付けるとか、
Key:=CStr(Worksheets("Sheet1").Cells(i, "A").Value)
のように、キーを明示的に String 型に揃えておくなどです。
Excel の場合、未入力セルは Empty 値を返す点にも注意が必要です。
' 空文字列と 数値 0 は区別される
Set x = CreateObject("Scripting.Dictionary")
x.Add "" , "A"
x.Add 0 , "B"
' Empty は、空文字列や数値 0 と合致してしまう
x.Add Empty, "C" '実行時エラー '457': このキーは既にこのコレクションの要素に割り当てられています。
Set y = CreateObject("Scripting.Dictionary")
y.Add Empty, "D"
y.Add "" , "E" '実行時エラー '457': このキーは既にこのコレクションの要素に割り当てられています。
Set z = CreateObject("Scripting.Dictionary")
z.Add Empty, "F"
z.Add 0 , "G" '実行時エラー '457': このキーは既にこのコレクションの要素に割り当てられています。
Dim a As Variant: a = 0
Dim b As Variant: b = ""
Dim c As Variant: c = #12:00:00 AM# '「1899/12/30 00:00:00」
Dim d As Variant: d = False
Dim e As Variant: e = Empty
Debug.Print "a="; TypeName(a) 'Integer
Debug.Print "b="; TypeName(b) 'String
Debug.Print "c="; TypeName(c) 'Date
Debug.Print "d="; TypeName(d) 'Boolean
Debug.Print "e="; TypeName(e) 'Empty
Debug.Print "*** 下記は False となる(空文字列は、数値ゼロとは別の値)"
Debug.Print b = a '"" は 0 ではない
Debug.Print b = c '"" は 正子 ではない
Debug.Print b = d '"" は False ではない
Debug.Print "*** 下記は True となる(Empty は、空文字列と数値ゼロの両方と同一視される)"
Debug.Print e = a 'Empty は 0 と等しい
Debug.Print e = b 'Empty は "" と等しい
Debug.Print e = c 'Empty は 正子 と等しい
Debug.Print e = d 'Empty は False と等しい
Debug.Print "*** 下記は True となる(正子、False、数値 0 は、いずれも同一値とみなされる)"
Debug.Print a = c
Debug.Print a = d
Debug.Print a = e
Debug.Print c = d
Debug.Print c = e
Debug.Print d = e
投稿者 KOZ  (社会人)
投稿日時
2023/7/26 17:25:55
キーを数値で登録し、文字列で取り出そうとしているからでは?
以下のコードは VB6 ですが、数値の 1 と、文字列の "1" は別物になっています。
登録するとき、セルの値を CStr で文字列に変換し、キーとして利用すれば良さそうです。
以下のコードは VB6 ですが、数値の 1 と、文字列の "1" は別物になっています。
Dim dic As Object
Set dic = CreateObject("Scripting.Dictionary")
dic.Add 1, "A"
dic.Add "1", "B"
Debug.Print dic(1)
Debug.Print dic("1")
結果
A
B
登録するとき、セルの値を CStr で文字列に変換し、キーとして利用すれば良さそうです。
投稿者 ヤマダ  (社会人)
投稿日時
2023/7/26 16:32:58
現在Excelのマクロを組んでいます。
題名の通りなのですが、セルから取得した値をキーにして値を連番で設定し、そのキーの値を取り出したいのですが、上手くいきません。
Type level_Data
levelCd As String
levelName As String
End Type
Dim levelCd As Object
Set levelCd = CreateObject("Scripting.Dictionary")
Dim levelNo As Long: levelNo = 1
Dim keyChk As String
Dim test_csv() As level_Data
xlLastRow = Cells(Rows.Count, LEVEL_NAME_SELL).Row
DtRowCnt = Worksheets("Sheet1").Cells(xlLastRow, "A").End(xlUp).Row
For i = 2 To DtRowCnt
If Not levelCd.Exists(Worksheets("Sheet1").Cells(i, "A").Value) Then
levelCd.Add Key:=Worksheets("Sheet1").Cells(i, "A").Value, _
Item:=levelNo
levelNo = levelNo + 1
End If
Next i
For i = 2 To DtRowCnt
keyChk = ""
keyChk = Worksheets("Sheet1").Cells(i, "A")
test_csv.levelName = Worksheets("Sheet1").Cells(i, "A")
test_csv.levelCd = levelCd.Item(keyChk)
Next i
セル値が数値の時に値が空白で帰ってくるのですが、数値はキーとして設定できないのでしょうか?
1や2がセル値にあり、それをキーとして設定し、その値を最終的には取り出せるようにしたいです。
よろしくお願いします。
題名の通りなのですが、セルから取得した値をキーにして値を連番で設定し、そのキーの値を取り出したいのですが、上手くいきません。
Type level_Data
levelCd As String
levelName As String
End Type
Dim levelCd As Object
Set levelCd = CreateObject("Scripting.Dictionary")
Dim levelNo As Long: levelNo = 1
Dim keyChk As String
Dim test_csv() As level_Data
xlLastRow = Cells(Rows.Count, LEVEL_NAME_SELL).Row
DtRowCnt = Worksheets("Sheet1").Cells(xlLastRow, "A").End(xlUp).Row
For i = 2 To DtRowCnt
If Not levelCd.Exists(Worksheets("Sheet1").Cells(i, "A").Value) Then
levelCd.Add Key:=Worksheets("Sheet1").Cells(i, "A").Value, _
Item:=levelNo
levelNo = levelNo + 1
End If
Next i
For i = 2 To DtRowCnt
keyChk = ""
keyChk = Worksheets("Sheet1").Cells(i, "A")
test_csv.levelName = Worksheets("Sheet1").Cells(i, "A")
test_csv.levelCd = levelCd.Item(keyChk)
Next i
セル値が数値の時に値が空白で帰ってくるのですが、数値はキーとして設定できないのでしょうか?
1や2がセル値にあり、それをキーとして設定し、その値を最終的には取り出せるようにしたいです。
よろしくお願いします。
>CompareMode プロパティが未設定なので、キー比較は BinaryCompare モードのままですね。
プロパティの設定を忘れていました。
大文字、小文字の区別は必要なので設定します。
>これは文法的に不自然ではありませんか?
失礼しました。
test_csv配列の要素数は他で宣言しており、その記述が抜けており困惑させてしまいました。
加えてかっこも抜けていました。
すみません。
>いいえ、数値もキーにできます。
しかし、キーのデータ型がブレるのは、あまりお勧めしません。
キーは常に同じ型に揃えておいた方が無難です。
特に数値型や Empty が渡される可能性がある場合はなおのこと。
Emptyが空文字列と合致するのは想像できていましたが、数値0と合致するのは驚きです。
今回はキーを明示的にString型に揃えておくことにします。
ありがとうございました。