Добавить три переменные в сценарий словаря задачи VBA - PullRequest
2 голосов
/ 05 июля 2019

Я довольно новичок в VBA (через 2 месяца) и пытаюсь добавить три переменные в словарь сценариев, чтобы переформатировать таблицу Excel, и у меня возникла ошибка.

Я попытался добавить три переменные

countrydict.Add country, data, time

Но я получаю сообщение об ошибке

Run-time error '450':
Wrong number of arguments or invalid property assignment

Однако это работает, если я пишу

countrydict.Add country, data 'or 
countrydict.Add country, time




Dim lastrow As Long
Dim iter As Long
Dim diter As Long
Dim countrydict As Object
Dim country As String
Dim data As String
Dim time As String
Dim key As Variant
Dim i As Long

Const StartRow As Byte = 2
lastrow = Range("A" & StartRow).End(xlDown).Row

Set countrydict = CreateObject("Scripting.Dictionary")

Dim diter2 As Long, arr, arr2

With ActiveSheet
For iter = 2 To lastrow
    country = Trim(.Cells(iter, 1).Value) '<<<<<
    data = Trim(.Cells(iter, 2).Value) '<<<<<
    time = Trim(.Cells(iter, 3).Text) '<<<<<
    If countrydict.Exists(country) Then
        If Not InStr(1, countrydict(country), data) > 0 Then

            countrydict(country) = countrydict(country) & _
                                   "|" & data & "/" & time
        End If
    Else
        countrydict.Add country, data, time '<<<<<<<
    End If
Next
    iter = 2
      For Each key In countrydict
    .Cells(iter, 1).Value = key & ":"
    .Cells(iter, 1).Font.Bold = True
    .Cells(iter, 1).Font.ColorIndex = 30
    iter = iter + 1
    arr = Split(countrydict(key), "|")
    For diter = 0 To UBound(arr)
        arr2 = Split(arr(diter), "/")
        .Cells(iter, 1).Value = arr2(0)
        .Cells(iter, 2).Value = arr2(1)
    Next diter
Next key
End With
End Sub

Ожидаемый результат - переформатировать таблицу в этом формате

"A"  "B"     "C"
EU  Sales   10:00
EU  Tax     12:00
USA Sales   09:00
USA Tax     10:00

В этот формат

EU: 
Sales 10:00
Tax   12:00 
USA:
Sales 09:00
Tax   10:00

Большое спасибо за любую помощь. Я боролся с этой проблемой в течение нескольких дней ...

Ответы [ 2 ]

2 голосов
/ 05 июля 2019

VBA имеет словарную структуру. Словарь - это объект , и на него можно ссылаться либо с ранним связыванием (например, Set countrydict = CreateObject("Scripting.Dictionary")), либо с поздним связыванием , ссылаясь на время выполнения сценариев Microsoft (В VBEditor> Дополнения> Библиотеки):

enter image description here

Преимущество последнего заключается в том, что он немного быстрее и нажимает Ctrl + пробел можно увидеть Intelli-Sense:

enter image description here

Что касается вопроса с несколькими переменными для словаря, то для массивас этим есть возможность:

Sub MyDictionary()

    Dim myDict As New Scripting.Dictionary

    If Not myDict.Exists("Slim") Then
        Debug.Print "Adding Slim"
        myDict.Add "Slim", Array("Eminem", "has", "a", "daughter!")
    End If

    If Not myDict.Exists("Barcelona") Then
        Debug.Print "Adding Barcelona"
        myDict.Add "Barcelona", Array("I", "have", "been there", 2018)
    End If

    If Not myDict.Exists("Barcelona") Then
        myDict.Add "Barcelona", Array("I", "have", "been there", 2018)
    Else
        Debug.Print "Barcelona already exists!"
    End If

    'Keys
    Dim key As Variant
    For Each key In myDict.Keys
        Debug.Print "--------------"
        Debug.Print "Key -> "; key
        Dim arrItem As Variant
        For Each arrItem In myDict(key)
            Debug.Print arrItem
        Next
    Next key

End Sub

Это результат кода:

Adding Slim
Adding Barcelona
Barcelona already exists!
--------------
Key -> Slim
Eminem
has
a
daughter!
--------------
Key -> Barcelona
I
have
been there
 2018 

Если значение словаря не является массивом, например, добавление куда-то myDict.Add "notArray", 124,при попытке напечатать массив возникнет ошибка.Этого можно избежать с помощью встроенной функции IsArray .

1 голос
/ 05 июля 2019

Другая возможность - создать новый класс для хранения ваших данных. Сохраните ваши данные в экземпляре этого класса, а затем передайте этот объект в словарь.

Таким образом, вы можете расширять класс по событию, чтобы он возвращал другие вещи, например, все значения в виде объединенной строки и т. Д. Используя публичные свойства, вы даже можете настроить проверку ввода, а что нет, но это, вероятно, больше, чем то, что есть. нужно прямо сейчас.
Я сохранил «Класс» до абсолютного минимума, обычно публичные переменные в классах плохие, но, поскольку мы используем его только как пользовательский тип данных, это не имеет значения.

Редактировать: Я немного обновил класс, чтобы показать некоторые дополнительные функциональные возможности, но оставляю старый здесь в качестве примера.

Стандартный модуль «Модуль1»:

Option Explicit

Sub fillDict()

    Dim adict As Scripting.Dictionary
    Set adict = New Dictionary

    Dim info As myRegionData
    Dim iter As Long

    For iter = 0 To 10
        Set info = New myRegionData

        info.Region = "someRegion" & iter
        info.data = "someData" & iter
        info.Time = "someTime" & iter

        adict.Add info.Region, info

    Next iter

    Dim returnInfo As myRegionData
    Set returnInfo = adict.Item("someRegion1")

    With returnInfo
        Debug.Print .Region, .data, .Time       'someRegion1   someData1     someTime1
        Debug.Print .fullSentence               'At someTime1 I was in someRegion1 and did someData1
    End With

End Sub

Модуль класса (простой) "myRegionData":

Option Explicit

Public Region As String
Public data As String
Public Time As String

Модуль класса (расширенный) "myRegionData":

Option Explicit

Private Type TmyRegionData
    'More about this structure:
    'https://rubberduckvba.wordpress.com/2018/04/25/private-this-as-tsomething/
    Region As String
    data As String
    Time As String
End Type
Private this As TmyRegionData


Public Property Get Region() As String
    Region = this.Region
End Property
Public Property Let Region(value As String)
    this.Region = value
End Property

Public Property Get data() As String
    data = this.data
End Property
Public Property Let data(value As String)
    this.data = value
End Property

Public Property Get Time() As String
    Time = this.Time
End Property
Public Property Let Time(value As String)
    this.Time = value
End Property


Public Function getFullSentence() As String
    getFullSentence = "At " & Time & " I was in " & Region & " and did " & data
End Function
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...