17

以前、Python で作業したことがありますが、リストの辞書を持つのは非常にスムーズです (つまり、1 つのキーが要素のリストに対応します)。vbaで同じことを達成するのに苦労しています。Excel シートに次のデータがあるとします。

Flanged_connections 6
Flanged_connections 8
Flanged_connections 10
Instrument  Pressure
Instrument  Temperature
Instrument  Bridle
Instrument  Others
Piping  1
Piping  2
Piping  3

Flanged_connectionsここで、データを読み取って、キーがでInstrumentありPiping、値が 2 番目の列の対応する値である辞書に格納します。データを次のようにしたい:

'key' 'values':

'Flanged_connections' '[6 8 10]'
'Instrument' '["Pressure" "Temperature" "Bridle" "Others"]'
'Piping' '[1 2 3]'

dict.Item("Piping")結果としてリストを使用してリストを取得でき[1 2 3]ます。だから私は次のようなことを考え始めました:

For Each row In inputRange.Rows

    If Not equipmentDictionary.Exists(row.Cells(equipmentCol).Text) Then
        equipmentDictionary.Add row.Cells(equipmentCol).Text, <INSERT NEW LIST>
    Else
        equipmentDictionary.Add row.Cells(equipmentCol).Text, <ADD TO EXISTING LIST>
    End If

Next

これを行うのは少し面倒に思えます。これに対するより良いアプローチはありますか?vbaで配列を使用して検索しようとしましたが、java、c++、pythonとは少し違うようで、stuft likeredim preserveなどがあります。これは、vba で配列を操作する唯一の方法ですか?

私の解決策:

@varocarbas のコメントに基づいて、コレクションの辞書を作成しました。これは、最も効率的ではないかもしれませんが、何が起こっているのかを理解するための最も簡単な方法です。他の解決策もおそらくうまくいくでしょう(私はテストしていません)。これは私の提案する解決策であり、正しい出力を提供します。

'/--------------------------------------\'
'| Sets up the dictionary for equipment |'
'\--------------------------------------/'

inputRowMin = 1
inputRowMax = 173
inputColMin = 1
inputColMax = 2
equipmentCol = 1
dimensionCol = 2

Set equipmentDictionary = CreateObject("Scripting.Dictionary")
Set inputSheet = Application.Sheets(inputSheetName)
Set inputRange = Range(Cells(inputRowMin, inputColMin), Cells(inputRowMax, inputColMax))
Set equipmentCollection = New Collection

For i = 1 To inputRange.Height
    thisEquipment = inputRange(i, equipmentCol).Text
    nextEquipment = inputRange(i + 1, equipmentCol).Text
    thisDimension = inputRange(i, dimensionCol).Text

    'The Strings are equal - add thisEquipment to collection and continue
    If (StrComp(thisEquipment, nextEquipment, vbTextCompare) = 0) Then
        equipmentCollection.Add thisDimension
    'The Strings are not equal - add thisEquipment to collection and the collection to the dictionary
    Else
        equipmentCollection.Add thisDimension
        equipmentDictionary.Add thisEquipment, equipmentCollection
        Set equipmentCollection = New Collection
    End If

Next

'Check input
Dim tmpCollection As Collection
For Each key In equipmentDictionary.Keys

    Debug.Print "--------------" & key & "---------------"
    Set tmpCollection = equipmentDictionary.Item(key)
    For i = 1 To tmpCollection.Count
        Debug.Print tmpCollection.Item(i)
    Next

Next

このソリューションは、すべての機器がソートされていることを前提としていることに注意してください!

4

3 に答える 3

9

VBA の配列は、多かれ少なかれ、さまざまな特殊性を備えた他の場所と似ています。

  • 配列のサイズ変更は可能です (必須ではありません)。
  • ほとんどの配列プロパティ ( SheetsWorkbook 内の配列など) は 1 から始まります。ただし、@TimWilliams によって正しく指摘されているように、ユーザー定義の配列は実際には 0 ベースです。以下の配列は、長さが 11 の文字列配列を定義します (10 は上位位置を示します)。

それと表記に関する特殊性を除けば、VBA 配列を扱う上で問題はありません。

Dim stringArray(10) As String
stringArray(1) = "first val"
stringArray(2) = "second val"
'etc.

要求しているものに関して、VBA で辞書を作成し、それにリストを含めることができます (または VBA に相当するもの: Collection)。ここにサンプル コードがあります。

Set dict = CreateObject("Scripting.Dictionary")
Set coll = New Collection
coll.Add ("coll1")
coll.Add ("coll2")
coll.Add ("coll3")
If Not dict.Exists("dict1") Then
    dict.Add "dict1", coll
End If

Dim curVal As String: curVal = dict("dict1")(3) '-> "coll3"

Set dict = Nothing 
于 2013-07-15T15:06:26.410 に答える
1

私は C++ と Python に慣れていないので (長い間)、VBA との違いについて話すことはできませんが、VBA で配列を操作することは特に複雑ではないと言えます。

私自身の謙虚な意見では、VBA で動的配列を操作する最善の方法は、ディメンションを多数に配置し、要素の追加が完了したら縮小することです。確かに、値を保存しながら配列のサイズを変更する Redim Preserve には、膨大なパフォーマンス コストがかかります。ループ内で Redim Preserve を使用しないでください。実行が非常に遅くなります。

例として与えられた次のコードを適応させます。

Sub CreateArrays()

Dim wS As Worksheet
Set wS = ActiveSheet

Dim Flanged_connections()
ReDim Flanged_connections(WorksheetFunction.CountIf(wS.Columns(1), _
    "Flanged_connections"))

For i = 1 To wS.Cells(1, 1).CurrentRegion.Rows.Count Step 1

    If UCase(wS.Cells(i, 1).Value) = "FLANGED_CONNECTIONS" Then   ' UCASE = Capitalize everything

        Flanged_connections(c1) = wS.Cells(i, 2).Value

    End If

Next i

End Sub
于 2013-07-15T15:05:41.013 に答える