programing

사전, 컬렉션 및 배열 비교

powerit 2023. 4. 13. 21:15
반응형

사전, 컬렉션 및 배열 비교

저는 컬렉션이나 배열에 비해 사전의 상대적인 장점과 특징을 알아내려고 합니다.

여기서 훌륭한 기사를 찾았는데, 다양한 기능을 모두 비교한 간단한 표를 찾을 수 없습니다.

아는 사람 있어요?

컬렉션과 사전을 편리하게 비교하려면 아래 표를 참조하십시오.

(이 표는 이 페이지를 "Early And Late binding" 섹션까지 요약한 것입니다.참고로 이 페이지에는 사전 사용에 대한 자세한 정보도 기재되어 있습니다.

요약하면 보통 사전이나 배열을 사용하는 것이 가장 좋습니다.

컬렉션 사용을 고려할 때 크기가 변경되지 않거나 거의 변경되지 않는 경우 어레이를 사용하는 것이 더 적절할 수 있습니다.이 경우 어레이는 컬렉션보다 효율적입니다.어레이는 모든 아이템을 한 번에 채우고 취득하는 데 매우 효율적이기 때문입니다(예를 들어 어레이에서 어레이로, 어레이에서 레인지로 되돌리는 등).

주의사항:

어레이에 비해 컬렉션은 아이템 추가 및 삽입, 키로 아이템 접근 및 삭제에 뛰어난 성능을 제공합니다.그러나 인덱스로 항목에 액세스하려면 성능이 떨어집니다.이를 효율적으로 수행하는 방법에 대한 자세한 내용은 이 목록 객체의 내부 작동에 대해서도 설명하는 여기를 참조하십시오.

이 cpearson 페이지에는 사전, 컬렉션 및 어레이를 사용하기 위한 매우 유용한 코드가 있습니다(이것들을 정렬하고 서로 변환합니다).

cpearson 페이지의 일부 텍스트:

Collection 개체와 Dictionary 개체는 관련 데이터 그룹을 저장하는 데 매우 유용합니다.다른 모든 조건이 동일하다면, 사용자가 사전에 있는 항목과 관련된 키 속성에 액세스(읽기, 쓰기, 변경)할 수 있기 때문에 Collection 개체 대신 Dictionary 개체를 사용합니다.다소 빈약한 객체 설계에서는 컬렉션에 있는 항목의 키가 쓰기 전용입니다.항목을 컬렉션에 추가할 때 항목에 키를 할당할 수 있지만 항목과 연결된 키를 가져올 수 없으며 컬렉션에 키가 있는지 직접 확인할 수도 없습니다.사전은 매우 친근하고 키로 열려 있다.사전은 또한 컬렉션보다 상당히 빠릅니다.

어레이를 선택하는 것이 좋지 않은 이유각 Redim이 메모리 블록 전체를 더 큰 위치에 복사하기 때문에 어레이의 크기 변경과 중간에 항목 삽입이 훨씬 느립니다.Preserve를 사용하면 모든 값도 복사됩니다.그 결과, 모든 조작에 대한 인식의 저하가 발생할 가능성이 있습니다(잠재적인 경우,

컬렉션과VBA 사전

Feature                 | COLLECTION | DICTIONARY | Remark
------------------------+------------+------------+--------------------------------
Usually faster          |            |     X      | 
------------------------+------------+------------+--------------------------------
Supported by VB Script  |            |     X      | Collections do not exist in VBS.
------------------------+------------+------------+--------------------------------
                        |            |            | Dicts: Add ref to Miscrosoft 
Native to VBA           |     X      |            | Scripting Library. Usage:
                        |            |            | Dim MyDict As Scripting.Dictionary
                        |            |            | Set MyDict = New Scripting.Dictionary
------------------------+------------+------------+--------------------------------
Can change Keys and     |            |            | Dict properties are writable.
Items                   |            |     X      | For collections, remove the item
                        |            |            | and add a new item.
------------------------+------------+------------+--------------------------------
                        |            |            | A collection enumerates its items:
                        |            |            |  For Each x In MyCollection
                        |            |            |      Debug.Print x
Enumerated              |     X      |     X      |  Next x
                        |            |            | A dict enumerates its keys:
                        |            |            |  For Each x In MyDictionary
                        |            |            |      Debug.Print MyDictionary.Item(x)
                        |            |            |  Next x
------------------------+------------+------------+--------------------------------
                        |            |            | A 1-d array of keys 
Directly output to      |            |            | and items can be returned by 
array                   |            |     X      | dict methods .Keys and .Items.
                        |            |            | (The array is zero-based even 
                        |            |            |  with Option Base 1.)
------------------------+------------+------------+--------------------------------
Retrieve and access     |     X      |     X      |
items                   |            |            |  
------------------------+------------+------------+--------------------------------
Add items               |     X      |     X      |
------------------------+------------+------------+--------------------------------
Implicitly add items    |            |     X      | Dicts can implicitly add items 
                        |            |            | using .Item property.
------------------------+------------+------------+--------------------------------
Remove items            |     X      |     X      |
------------------------+------------+------------+--------------------------------
Remove all items in     |            |            | With collections, each item must
one step                |            |     X      | be removed in turn, or the 
                        |            |            | collection destroyed and recreated.
------------------------+------------+------------+--------------------------------
Count items             |     X      |     X      |
------------------------+------------+------------+--------------------------------
Return item using key   |     X      |     X      |
as lookup value         |            |            |
------------------------+------------+------------+--------------------------------
Return item using       |            |            |
ordinal position        |     X      |   (Slow)   |
as lookup value         |            |            |
------------------------+------------+------------+--------------------------------
Return ordinal          |            |            |
position using item     |     X      |     ??     |
as lookup value         |            |            |
------------------------+------------+------------+--------------------------------
Retrieve and access     |            |     X      | Collection keys only used to
keys                    |            |            | look up data, not retrievable.
------------------------+------------+------------+--------------------------------
Keys optional           |     X      |            | Big + of collections, assuming keys
                        |            |            | are not needed. (Access via index.)
------------------------+------------+------------+--------------------------------
Case sensitivity        |            |     X      |
optional                |            |            |  
------------------------+------------+------------+--------------------------------
                        |            |            | Collection keys must be strings.
Keys can be any type    |            |     X      | Dict keys can have any type
                        |            |            | (except arrays), incl. mixed types.
------------------------+------------+------------+--------------------------------
Keys must be unique     |     X      |     X      |
------------------------+------------+------------+--------------------------------
                        |            |            | * For collections, add code:
                        |            |            |  Public Function _
                        |            |            |     Contains(col As Collection, _
Supports .Exists method |  Remark*   |     X      |     key As Variant) As Boolean
                        |            |            |     On Error Resume Next
                        |            |            |     col(key)
                        |            |            |     Contains = (Err.Number = 0)
------------------------+------------+------------+--------------------------------
Preserve key order when |            |     X      | This is because collection keys 
sorting by item value   |            |            | are write-only, not read. Poor design!

원본 이미지: 더 많은 정보가 있고 더 선명하게 배열되어 있습니다.

비교표 이미지

Option Explicit

Sub CollectionsVSdictionaries() ' Requires ref to "Microsoft Scripting Runtime" Library
    Dim c As Collection         ' TypeName 1-based indexed
    Dim d As Dictionary         ' 0-based arrays
    Set c = New Collection      ' or: "Dim c As New Collection"
    Set d = New Dictionary      ' or: "Dim d As New Dictionary"

    c.Add Key:="A", Item:="AA": c.Add Key:="B", Item:="BB": c.Add Key:="C", Item:="CC"
    d.Add Key:="A", Item:="AA": d.Add Key:="B", Item:="BB": d.Add Key:="C", Item:="CC"

    Debug.Print TypeName(c)    ' -> "Collection"
    Debug.Print TypeName(d)    ' -> "Dictionary"

    Debug.Print c(3)            ' -> "CC"
    Debug.Print c("C")          ' -> "CC"
    'Debug.Print c("CC")       ' --- Invalid ---

    Debug.Print d("C")          ' -> "CC"
    Debug.Print d("CC")        ' Adds Key:="CC", Item:=""
    Debug.Print d.Items(2)      ' -> "CC"
    Debug.Print d.Keys(2)       ' -> "C"
    Debug.Print d.Keys()(0)     ' -> "A"    - Not well known ***************************
    Debug.Print d.Items()(0)    ' -> "AA"   - Not well known ***************************

    'Collection methods:
    '    .Add                   ' c.Add Item, [Key], [Before], [After] (Key is optional)
    '    .Count
    '    .Item(Index)           ' Default property;   "c.Item(Index)" same as "c(Index)"
    '    .Remove(Index)
    'Dictionary methods:
    '    .Add                   ' d.Add Key, Item (Key is required, and must be unique)
    '    .CompareMode           ' 1. BinaryCompare     - case-sensitive   ("A" < "a")
    '    .CompareMode           ' 2. DatabaseCompare   - MS Access only
    '    .CompareMode           ' 3. TextCompare       - case-insensitive ("A" = "a")
    '    .Count
    '    .Exists(Key)           ' Boolean **********************************************
    '    .Item(Key)
    '    .Items                 ' Returns full array: .Items(0)(0)
    '    .Key(Key)
    '    .Keys                  ' Returns full array: .Keys(0)(0)
    '    .Remove(Key)
    '    .RemoveAll             ' ******************************************************
End Sub

컬렉션과 사전의 퍼포먼스에 대해서는 사전에 쓰는 것은 컬렉션에 쓰는 것과 비슷하고, 사전에서 읽는 것은 컬렉션에서 읽는 것보다 약 2배 정도 시간이 걸리는 것을 알 수 있었습니다.처음에 사전을 만드는 것은 컬렉션을 만드는 것보다 훨씬 느립니다.

사전/컬렉션의 읽기, 쓰기 및 작성을 10만 번 반복한 결과 다음과 같습니다.

Creating Multiple Dictionaries:   731ms
Writing To Dictionary:            494ms
Reading From Dictionary:           65ms

Creating Multiple Collections:     29ms
Writing To Collection:            459ms
Reading From Collection:           26ms

Microsoft Scripting Runtine에 대한 참조를 추가하면 여러 사전을 만드는 속도가 향상됩니다(여기는 495ms).

테스트에 사용한 코드는 다음과 같습니다.

Option Explicit

Private p_lngTestCount As Long

Sub SetUp()
  p_lngTestCount = 100000
End Sub

Sub TestAll()
  CreatingMultipleDictionaries
  WritingToDictionary
  ReadingFromDictionary

  CreatingMultipleCollections
  WritingToCollection
  ReadingFromCollection
End Sub

Sub CreatingMultipleDictionaries()

  Const sSOURCE As String = "CreatingMultipleDictionaries"

  Dim oPerfMon As CDevPerformanceMonitor
  Set oPerfMon = New CDevPerformanceMonitor
  Dim i As Long
  Dim dcTest As Dictionary
  SetUp

  Dim dblTimeElapsed As Double
  oPerfMon.StartCounter

  For i = 0 To p_lngTestCount
    'Set dcTest = CreateObject("Scripting.Dictionary")
    Set dcTest = New Dictionary
  Next i

  dblTimeElapsed = oPerfMon.TimeElapsed

  Debug.Print sSOURCE & ": " & p_lngTestCount & " iterations. " & vbCrLf & _
              "Time elapsed: " & Round(dblTimeElapsed, 0) & "ms" & vbCrLf
End Sub

Sub CreatingMultipleCollections()

  Const sSOURCE As String = "CreatingMultipleCollections"

  Dim oPerfMon As CDevPerformanceMonitor
  Set oPerfMon = New CDevPerformanceMonitor
  Dim i As Long
  Dim colTest As Collection
  SetUp

  Dim dblTimeElapsed As Double
  oPerfMon.StartCounter

  For i = 0 To p_lngTestCount
    Set colTest = New Collection
  Next i

  dblTimeElapsed = oPerfMon.TimeElapsed

  Debug.Print sSOURCE & ": " & p_lngTestCount & " iterations. " & vbCrLf & _
              "Time elapsed: " & Round(dblTimeElapsed, 0) & "ms" & vbCrLf
End Sub

Sub WritingToDictionary()

  Const sSOURCE As String = "WritingToDictionary"

  Dim oPerfMon As CDevPerformanceMonitor
  Set oPerfMon = New CDevPerformanceMonitor
  Dim i As Long
  Dim dcTest
  SetUp

  Set dcTest = CreateObject("Scripting.Dictionary")
  'Set dcTest = New Dictionary

  Dim dblTimeElapsed As Double
  oPerfMon.StartCounter

  For i = 0 To p_lngTestCount
   ' Performance about the same for both ways:
    dcTest.Item(CStr(i)) = "test"
    'dcTest.Add CStr(i), "test"
  Next i

  dblTimeElapsed = oPerfMon.TimeElapsed

  Debug.Print sSOURCE & ": " & p_lngTestCount & " iterations. " & vbCrLf & _
              "Time elapsed: " & Round(dblTimeElapsed, 0) & "ms" & vbCrLf
End Sub

Sub WritingToCollection()

  Const sSOURCE As String = "WritingToCollection"

  Dim oPerfMon As CDevPerformanceMonitor
  Set oPerfMon = New CDevPerformanceMonitor
  Dim i As Long
  Dim colTest As Collection
  SetUp

  Dim dblTimeElapsed As Double
  Set colTest = New Collection

  oPerfMon.StartCounter

  For i = 0 To p_lngTestCount
    colTest.Add "test", CStr(i)
  Next i

  dblTimeElapsed = oPerfMon.TimeElapsed

  Debug.Print sSOURCE & ": " & p_lngTestCount & " iterations. " & vbCrLf & _
              "Time elapsed: " & Round(dblTimeElapsed, 0) & "ms" & vbCrLf
End Sub

Sub ReadingFromDictionary()

  Const sSOURCE As String = "ReadingFromDictionary"

  Dim oPerfMon As CDevPerformanceMonitor
  Set oPerfMon = New CDevPerformanceMonitor
  Dim i As Long
  Dim dcTest
  SetUp

  Set dcTest = CreateObject("Scripting.Dictionary")
  'Set dcTest = New Dictionary
  dcTest.Add "key", "test"

  Dim stTest As String
  Dim dblTimeElapsed As Double

  oPerfMon.StartCounter

  For i = 0 To p_lngTestCount
    stTest = dcTest.Item("key")
  Next i

  dblTimeElapsed = oPerfMon.TimeElapsed

  Debug.Print sSOURCE & ": " & p_lngTestCount & " iterations. " & vbCrLf & _
              "Time elapsed: " & Round(dblTimeElapsed, 0) & "ms" & vbCrLf
End Sub

Sub ReadingFromCollection()

  Const sSOURCE As String = "ReadingFromCollection"

  Dim oPerfMon As CDevPerformanceMonitor
  Set oPerfMon = New CDevPerformanceMonitor
  Dim i As Long
  Dim colTest As Collection
  SetUp

  Dim stTest As String
  Dim dblTimeElapsed As Double
  Set colTest = New Collection
  colTest.Add "test", "key"

  oPerfMon.StartCounter

  For i = 0 To p_lngTestCount
    stTest = colTest.Item("key")
  Next i

  dblTimeElapsed = oPerfMon.TimeElapsed

  Debug.Print sSOURCE & ": " & p_lngTestCount & " iterations. " & vbCrLf & _
              "Time elapsed: " & Round(dblTimeElapsed, 0) & "ms" & vbCrLf
End Sub

퍼포먼스 모니터클래스(CDev Performance Monitor):

Option Explicit

' Performance monitoring used in logging
' See: https://stackoverflow.com/questions/198409/how-do-you-test-running-time-of-vba-code

Private Type LARGE_INTEGER
  lowpart As Long
  highpart As Long
End Type

#If VBA7 Then
  Private Declare PtrSafe Function QueryPerformanceCounter Lib "kernel32" (lpPerformanceCount As LARGE_INTEGER) As Long
#Else
  Private Declare Function QueryPerformanceCounter Lib "kernel32" (lpPerformanceCount As LARGE_INTEGER) As Long
#End If

#If VBA7 Then
  Private Declare PtrSafe Function QueryPerformanceFrequency Lib "kernel32" (lpFrequency As LARGE_INTEGER) As Long
#Else
  Private Declare Function QueryPerformanceFrequency Lib "kernel32" (lpFrequency As LARGE_INTEGER) As Long
#End If

Private m_CounterStart As LARGE_INTEGER
Private m_CounterEnd As LARGE_INTEGER
Private m_crFrequency As Double

Private Const TWO_32 = 4294967296#               ' = 256# * 256# * 256# * 256#

Private Function LI2Double(LI As LARGE_INTEGER) As Double
  Dim Low As Double
  Low = LI.lowpart
  If Low < 0 Then
    Low = Low + TWO_32
  End If
  LI2Double = LI.highpart * TWO_32 + Low
End Function

Private Sub Class_Initialize()
  Dim PerfFrequency As LARGE_INTEGER
  QueryPerformanceFrequency PerfFrequency
  m_crFrequency = LI2Double(PerfFrequency)
End Sub

Public Sub StartCounter()
  QueryPerformanceCounter m_CounterStart
End Sub

Public Function PerformanceCount() As Double
  Dim liPerformanceCount As LARGE_INTEGER
  QueryPerformanceCounter liPerformanceCount
  PerformanceCount = LI2Double(liPerformanceCount)
End Function

Public Function MicroTime() As Double
  MicroTime = Me.PerformanceCount * 1000000# / m_crFrequency
End Function

Public Property Get TimeElapsed() As Double
  Dim crStart As Double
  Dim crStop As Double
  QueryPerformanceCounter m_CounterEnd
  crStart = LI2Double(m_CounterStart)
  crStop = LI2Double(m_CounterEnd)
  TimeElapsed = 1000# * (crStop - crStart) / m_crFrequency
End Property
Option Explicit

Sub UpdateSummary()

    Dim varData
    Dim objDicCountry As Object
    Dim objDicCity As Object
    Dim objDicData As Object
    Dim lngR As Long
    Dim varResult
    Dim lngC As Long
    Dim strKey As String
    Dim varUnique

    varData = Sheet12.Range("A1").CurrentRegion
    Set objDicCity = CreateObject("Scripting.Dictionary")
    Set objDicCountry = CreateObject("Scripting.Dictionary")
    Set objDicData = CreateObject("Scripting.Dictionary")

    For lngR = LBound(varData) + 1 To UBound(varData)

        strKey = varData(lngR, 1) '--Country
        objDicCountry.Item(strKey) = ""

        strKey = varData(lngR, 2) '--City
        objDicCity.Item(strKey) = ""

        strKey = varData(lngR, 1) & "|" & varData(lngR, 2) '--Country and City
        objDicData.Item(strKey) = objDicData.Item(strKey) + varData(lngR, 3)

    Next lngR

    ReDim varResult(1 To objDicCountry.Count + 1, 1 To objDicCity.Count + 1)

    varUnique = objDicCountry.keys '--get Unique Country

    For lngR = LBound(varUnique) To UBound(varUnique)
        varResult(lngR + 2, 1) = varUnique(lngR)
    Next lngR

    varUnique = objDicCity.keys '--get Unique City

    For lngC = LBound(varUnique) To UBound(varUnique)
        varResult(1, lngC + 2) = varUnique(lngC)
    Next lngC


    For lngR = LBound(varResult) + 1 To UBound(varResult)
        For lngC = LBound(varResult) + 1 To UBound(varResult, 2)
            strKey = varResult(lngR, 1) & "|" & varResult(1, lngC) '--Country & "|" & City
            varResult(lngR, lngC) = objDicData.Item(strKey)
        Next lngC
    Next lngR

    Sheet12.Range("F6").Resize(UBound(varResult), UBound(varResult, 2)).Value = varResult
    MsgBox "Done", vbInformation

End Sub

언급URL : https://stackoverflow.com/questions/32479842/comparison-of-dictionary-collections-and-arrays

반응형