2015-12-07 5 views
0

Я пытаюсь создать словарь списков. Я привык к этому в python, но в vba у меня возникают трудности. данные в колонках А и В (я буду использовать диапазон с конца (xldown) вместо жесткого кодирования A1: A4 это только в качестве примера), и они выглядят примерно так:Создание словаря с VBA

A Apple 
A Banana 
B Carrot 
B Juice 

По существу я m, желающий создать словарь, который выглядит (в формате python как: {A: [Apple, Bannana], B: [Carrot, Juice]}

Конечным результатом является то, что я хочу вставить значения словаря в другой столбец C, который будет выглядеть следующим образом:

A Apple Apple/Banana 
A Banana Apple/Banana 
B Carrot Carrot/Juice 
B Juice Carrot/Juice 

Я пытался используя вложенный цикл через varrays, но он не распознал относительные позиции столбца A и B. Мне было интересно, что лучший способ сделать это в VBA?
Спасибо.

ответ

1

Вы можете использовать только VBA или смешивать с UDF.

Рассмотрим первоначально у вас есть (чтобы продемонстрировать один из вариантов):
sampledata

Создайте модуль и поместить его в:

Option Explicit 

Private lRow As Long 
Private oDict As Object 

Private Sub CreateDict() 
    Dim arrValues As Variant, oKey As Variant, oValue As Variant, i As Long 

    If oDict Is Nothing Then 
     lRow = Worksheets("Sheet2").UsedRange.Rows.Count 
     Set oDict = CreateObject("Scripting.Dictionary") 
    Else 
     If lRow <> Worksheets("Sheet2").UsedRange.Rows.Count Then oDict.RemoveAll ' Remove old items 
    End If 
    ' Add items to the dictionary 
    ' Load values of used range to memory 
    arrValues = Worksheets("Sheet2").UsedRange.Value 
    ' Assuming the Key is on first column and Value is on next 
    For i = 1 To UBound(arrValues) 
     oKey = arrValues(i, 1) 
     oValue = arrValues(i, 2) 
     If Len(oKey) > 0 Then 
      If oDict.Exists(oKey) Then 
       ' Append Value to existing key 
       oDict.Item(oKey) = oDict.Item(oKey) & "/" & oValue 
      Else 
       ' Add Key and value 
       oDict.Add oKey, oValue 
      End If 
     End If 
    Next 
End Sub 

Function GetList(ByVal oRange As Range) As String 
    If lRow <> Worksheets("Sheet2").UsedRange.Rows.Count Then Set oDict = Nothing 
    If oDict Is Nothing Then CreateDict 
    GetList = oDict.Item(oRange.Value) 
End Function 

Макрос выше, чтобы создать список словарей. Затем в следующем столбце используйте формулу для вызова UDF GetList, например.
Stage1

Auto Fill ОДС, чтобы получить результат, который вы хотите:
Stage2


Есть плюсы и минусы с помощью UDF, но я полагаю, вы можете изменить его только VBA (новый Sub и цикл через первый столбец).

+0

Это довольно много места на. Итак, моя проблема заключалась в том, что вы должны явно убедиться, что ссылки находятся в массиве с помощью arrValues. Большое спасибо за этот обучающий момент. И да, было легко изменить его только на VBA, но приятно видеть этот вариант. – FancyDolphin

+0

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

-1

Используя комбинацию формул и VBA, вы можете достичь ожидаемых результатов. Начиная с ячейкой C1, а затем перетащить вниз до конца вашего стола места следующей формулы:

=stringconcat("/",IF($A:$A=A1,$B:$B,"")) 

Это вставляется как формула массива с помощью CTRL + SHIFT + ENTER. Объясняя логику из IF, для каждой строки в столбце A:A, которая равна значению этой строки («A» в представленном примере), она будет извлекать ее в массив (возврат, если истинный вариант в IF). Лучшая часть этого заключается в том, что вам не нужно жестко кодировать диапазон, поскольку мы рассматриваем весь столбец.

Этот массив затем сцепляется с помощью чип-Pearsons удобной функции, которую можно найти здесь:

http://www.cpearson.com/excel/stringconcatenation.aspx

Включать код он любезно предлагает в модуль, и вы до гонок.

+0

В то время как олень ценится, если бы я шел по маршруту электронной таблицы. Это можно было сделать проще. Я мог бы создать уникальный индекс, использовать счетчик длины и объединить с командой if. Тем не менее, это беспорядочно, и я предпочел бы, чтобы это было сделано исключительно VBA в эффективном диапазоне данных, а не в целом столбце, в котором будет использоваться справедливый бит ресурсов. – FancyDolphin

0

Как уже говорило PatricK, в VBA есть словари, но только через скрипты, а не так хорошо интегрированы в язык, как в Python (Бог, я скучаю по этим спискам и словарям).Этот метод обычно работает, но требует ссылки на сценарий или использование позднего связывания, как показывает PatricK.

В качестве альтернативы вы можете использовать коллекцию классов. Определите модуль класса и передайте ему некоторые переменные, один из которых - Collection. Таким образом, вы можете прокрутить свою коллекцию классов, чтобы найти букву индекса (A и B в этом примере) и извлечь список фруктов из сохраненного класса.

Я нахожу этот метод более гибким и масштабируемым (у вас есть полный контроль над модулем класса). И это «родное» решение, которое будет работать на любой машине, а также на Mac (где иногда иногда бывает больно).

Если вы хотите, я могу подробно остановиться на примере, но я никогда не смогу быть таким же полным, как Чип Пирсон на его site.

+0

Очень хороший указатель для расширенного использования VBA и Mac-недружественного кода ... Вы нашли существующие коды с помощью Collection для реализации Scripting.Dictionary? Существует множество методов, которые могут быть слишком сложными, чтобы сделать его совместимым с Mac. – PatricK

+0

Правда, иногда это не стоит хлопот. Но 9 из 10 раз я использую словарь, который в конце концов переписываю его, потому что я хочу сделать что-то, чего не может сделать словарь. И набор классов - это не такая уж большая проблема. Знаете ли вы, что вы можете назначить ключ переменной коллекции в vba? Не очень полезно в большинстве случаев, но все же, для некоторых случаев, оно имеет свои применения. – Jzz

Смежные вопросы