Как отобразить указанные c значения ячеек при использовании словаря в VBA? - PullRequest
0 голосов
/ 26 февраля 2020

Я немного новичок в использовании словаря, поэтому буду признателен за любую помощь, расширенную в этой области. У меня есть информация о сотруднике в листе Excel то есть Col A до Col BD. Созданный ключ представляет собой комбинацию имени, отдела и класса. Мне нужно отобразить различные атрибуты сотрудника, такие как DOJ, пройденное обучение и т. Д. c, когда пользователь выбирает сотрудника, отображаемого в поле со списком формы. Мне удалось создать ключ в словаре. Если я читаю конкретную строку (нет) как Значение и Ключ как вышеприведенную комбинацию, как мне тогда отображать определенные c атрибуты выбранного сотрудника. Listbox отображает ту же комбинацию, что и созданный ключ, т. Е. Name, Dept и Grade

. Любые идеи по этому поводу приветствуются.

Я сделал это, используя массивы, но когда размер диапазона увеличивается, поиск массива замедляет общую производительность. Поэтому рассматривал использование словаря

varArray_TP - это массив, который содержит все данные. В списке отображается имя, оценка и отдел сотрудника. Эта комбинация сохраняется в массиве с | в качестве разделителя. Когда пользователь выбирает параметр из списка, он проверяется по ключу в массиве для отображения других атрибутов из массива.

' loading the data into the array
For i = 1 To TotalRows_TP
  For j = 1 To TotalCols_TP
   varArray_TP(i, j) = Sheets("TP").Cells(i + 1, j).Value
  Next j
Next i

' generating the key for each row in the array
For i = 1 To TotalRows_TP
  varArray_TP(i, TotalCols_TP + 1) = 
    WorksheetFunction.Concat( _
      ThisWorkbook.Sheets("TP").Range("C" & i + 1).Value, "|", _
      ThisWorkbook.Sheets("TP").Range("D" & i + 1).Value, "|", _
      ThisWorkbook.Sheets("TP").Range("AP" & i + 1).Value _
   )
Next i

' find the data based on the selected key
Sub Profile_Details()
  Dim i As Integer
  Dim j As Integer
  With UserForm1
    If .vLB_SearchValues.ListIndex > -1 And .vRb_ByName.Value = True Then
      For i = 1 To TotalRows_TP

        If varArray_TP(i, TotalCols_TP + 1) = WorksheetFunction.Concat( _
          .vLB_SearchValues.List(.vLB_SearchValues.ListIndex, 0), "|", _
          .vLB_SearchValues.List(.vLB_SearchValues.ListIndex, 1), "|", _
          .vLB_SearchValues.List(.vLB_SearchValues.ListIndex, 2) _
        ) Then

          .vLB_Grade.Caption = varArray_TP(i, 4)
          .vLB_PositionTitle.Caption = varArray_TP(i, 33)
          .vLB_Dateentered_JobGrade.Caption = varArray_TP(i, 7)
          .vLB_PersonnelArea.Caption = varArray_TP(i, 42)
          .vLB_Dateentered_Position.Caption = varArray_TP(i, 6)
          .vLB_BizRating.Caption = varArray_TP(i, 25)
          .vLB_PplRating.Caption = varArray_TP(i, 26)
          .vLB_UltimatePotential.Caption = varArray_TP(i, 10)
          .vLB_Name.Caption = varArray_TP(i, 3)
          UserForm2.vLB_TalentNaForm2.Caption = "Talent Name : " & .vLB_Name.Caption

        End If
      Next i
    End If

  End With
End Sub

Ниже приведен пример таблицы данных (разделены табуляцией):

User ID Name - LFM  Job Grade   Comp Grade  Date Entered Position   Date Entered Job Grade  Personnel   Area
T22MXIQ  Pillay Avinash 8   07  7-1-2015    7-1-2015    PU03 - JD   India Technology Center
B19CXIV Baishali    08  07  7-1-2015    7-1-2015    PU03 - JD   India Technology Center
B22MXIR Bhargavi    08  07  7-1-2015    7-1-2015    PU03 - JD   India Technology Center
T22MXIG Ghosh Anurag    09  07  7-1-2015    7-1-2015    PU03 - JD   India Technology Center
PU00177 Kadam Ashok 08  07  7-1-2015    7-1-2015    PU03 - JD   India Technology Center
PU00178 Kadam Sushma    03  07  7-1-2015    7-1-2015    PU03 - JD   India Technology Center
PU00180 Kadam Sushma    08  07  7-1-2015    7-1-2015    PU03 - JD   India Technology Center
M22MXIL Mugdha  08  07  7-1-2015    7-1-2015    PU03 - JD   India Technology Center
PU00179 Pandey Shobha   06  07  7-1-2015    7-1-2015    PU03 - JD   India Technology Center
T22MXIS Sanjyot 03  07  7-1-2014    7-1-2018    PU02 - JD   China Technology Center
T22MXIP Shah Pradnesh   07  07  7-1-2015    7-1-2015    PU03 - JD   India Technology Center
T22MXPS Shah Pradnesh   06  07  7-1-2015    7-1-2015    PU03 - JD   India Technology Center
T22MXUS Sushma  03  07  7-1-2015    7-1-2015    PU03 - JD   India Technology Center
T22MXVI Vrushali    08  08  7-1-2015    7-1-2015    PU02 - JD   China Technology Center

Мне нужно показать только список сотрудников, которые соответствуют имени, напечатанному в текстовом поле, используя поиск строки, поэтому я использовал приведенный ниже код. В случае, если у вас есть лучший подход, это будет приветствоваться, так как я все еще перебираю ключи, поэтому я предполагаю, есть ли оптимальная возможность поиска, когда я не нажимаю oop несколько раз

str = UserForm1.vTB_SearchString.Text
  UserForm1.vLB_SearchValues.Clear

  With UserForm1
  If .vRb_ByName.Value = True Then
  UserForm1.vLB_SearchValues.ColumnWidths = "2.2 in; 0.5 in; 2.8 in"

For Each EmpKey In EmployeeDict.Keys
 EmpParts = Split(EmpKey, "|")
    If InStr(1, EmpParts(0), str, vbTextCompare) Then
    .vLB_SearchValues.AddItem
    .vLB_SearchValues.List(.vLB_SearchValues.ListCount - 1, 0) = EmpParts(0)
    .vLB_SearchValues.List(.vLB_SearchValues.ListCount - 1, 1) = EmpParts(1)
    .vLB_SearchValues.List(.vLB_SearchValues.ListCount - 1, 2) = EmpParts(2)
    End If
Next

1 Ответ

0 голосов
/ 27 февраля 2020

Вы, конечно, можете использовать словарь здесь, и я бы даже go сказал бы, что вы должны. Не для производительности (хотя словарь более производительный), а потому, что гораздо проще вернуть значение из словаря, чем l oop по массиву, ищущему соответствующий ключ.

Но я бы хотел Предположим, что основная причина проблем с производительностью заключается в следующем: когда вы используете объекты Excel (рабочие таблицы, диапазоны, функции рабочих таблиц) и их свойства и методы, обычно это на несколько порядков медленнее, чем при использовании чистых альтернатив VBA. В частности:

  • Вместо загрузки данных путем зацикливания ячеек с varArray_TP(i, j) = Sheets("TP").Cells(i + 1, j).Value в al oop, объект Excel Range поддерживает непосредственное создание двумерного массива:

    Dim varArray_TP As Variant
    varArray_TP = Sheets("TP").Range("R1C1:R" & TotalRows_TP & "C" & TotalCols_TP)
    

    Следует признать, что размеры этого массива фиксированы в зависимости от размера диапазона, и у нас не будет дополнительного столбца для хранения ключа в массиве; но если мы используем словарь, нам не нужно это делать.

  • Не используйте WorksheetFunction.Concat. Вместо этого используйте оператор конкатенации строк VBA - &. Например, чтобы сгенерировать ключ для данного row числа в массиве:

    key = varArray_TP(row, 3) & "|" & varArray_TP(row, 4) & "|" & varArray_TP(row, 42)
    

В следующем коде показано, как использовать словарь. Добавьте ссылку на Microsoft Scripting Runtime из Инструменты -> Ссылки ... . Затем определите ваш словарь в том же месте, в котором вы определили массив:

Dim dict As New Scripting.Dictionary

Затем:

Dim wks As Worksheet
Set wks = Sheets("TP")

' load data into array
Dim varArray_TP As Variant
varArray_TP = wks.Range( _
    wks.Cells(1, 1), _
    wks.Cells(TotalRows, TotalCols) _
)

' fill the dictionary
' the key for each entry will be the Name, Grade and Dept, separated by |
' the corresponding value will be the first index of that person's data within the array
Dim rows as Long
rows = UBound(varArray_TP, 1)
Dim row As Long, key As String
For row = 1 To rows
    key = varArray_TP(row, 3) & "|" & varArray_TP(row, 4) & "|" & varArray_TP(row, 42)
    dict(key) = row
Next

Там по-прежнему не хватает фрагмента: как заполнить список с помощью ключи? Вы можете сделать что-то вроде этого:

Dim key As Variant
For Each key In dict.Keys
    Dim parts() As String
    parts = Split(key, "|")

    ' parts is now a 1-dimensional array, with the Name, Dept and Grade
    ' TODO fill the listbox with the individual parts

Next

Затем, когда вы хотите получить подробности, вы можете сделать что-то вроде этого:

' find the data based on the selected key
Sub Profile_Details()
    With UserForm1
        If .vLB_SearchValues.ListIndex > -1 And .vRb_ByName.Value = True Then
            Dim row As Long
            row = dict( _
                .vLB_SearchValues.List(.vLB_SearchValues.ListIndex, 0) & "|" & _
                .vLB_SearchValues.List(.vLB_SearchValues.ListIndex, 1) & "|" & _
                .vLB_SearchValues.List(.vLB_SearchValues.ListIndex, 2) _
            )

           .vLB_Grade.Caption = varArray_TP(row, 4)
           .vLB_PositionTitle.Caption = varArray_TP(row, 33)
           .vLB_Dateentered_JobGrade.Caption = varArray_TP(row, 7)
           .vLB_PersonnelArea.Caption = varArray_TP(row, 42)
           .vLB_Dateentered_Position.Caption = varArray_TP(row, 6)
           .vLB_BizRating.Caption = varArray_TP(row, 25)
           .vLB_PplRating.Caption = varArray_TP(row, 26)
           .vLB_UltimatePotential.Caption = varArray_TP(row, 10)
           .vLB_Name.Caption = varArray_TP(row, 3)
           UserForm2.vLB_TalentNaForm2.Caption = "Talent Name : " & .vLB_Name.Caption

        End If
    End With
End Sub

После написания всего этого Я понял, что вы можете сделать что-то попроще: вы можете сохранить номер строки в самом списке, как скрытый столбец, и использовать это число для извлечения данных из массива. Это означает, что вам не нужен словарь.


Для получения дополнительной информации о Scripting.Dictionary см. здесь .

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...