Вот функции, определенной пользователем подход, который я упомянул (адаптировано из другого ВПР-варианта Я уже сделал):
' Acts like VLOOKUP in a 1-to-many scenario by concatenating all values in matching rows
' instead of just returning the first match
Public Function VLOOKUP_MANY(lookup_value As String, lookup_range As Range, column_number As Integer, Optional delimiter As Variant) As Variant
Dim vArr As Variant
Dim i As Long
Dim found As Boolean: found = False
' Set default delimiter
If IsMissing(delimiter) Then delimiter = ", "
' Get values
vArr = lookup_range.Value2
' If column_number is outside of the specified range, return #REF
If column_number < LBound(vArr, 2) Or column_number > UBound(vArr, 2) Then
VLOOKUP_MANY = CVErr(xlErrRef)
Exit Function
End If
' Search for matches and build a concatenated list
VLOOKUP_MANY = ""
For i = 1 To UBound(vArr, 1)
If UCase(vArr(i, 1)) = UCase(lookup_value) Then
VLOOKUP_MANY = VLOOKUP_MANY & delimiter & vArr(i, column_number)
found = True ' Mark at least 1 result
End If
Next
If found Then
VLOOKUP_MANY = Right(VLOOKUP_MANY, Len(VLOOKUP_MANY) - Len(delimiter)) ' Remove first delimiter
Else
VLOOKUP_MANY = CVErr(xlErrNA) ' If no matches found, return #N/A
End If
End Function
Это будет искать первый столбец в заданном диапазоне для заданного значения (такого же, как ВПР), но возвращаю значения в указанном номере столбца каскадного. Он вернет # N/A, если совпадений не найдено, и #REF, если для номера столбца указано недопустимое значение (например, вы выбираете столбец 5, но только столбец с четырьмя столбцами).
Если вы не знаете о пользовательских функциях, вы можете просто скопировать этот код VBA в VBE для модуля в вашей книге. Нажмите Alt + F11, перейдите в Insert > Module
в верхней части экрана, затем вставьте этот код в пустой файл, который открывается. Когда вы переходите на сохранение, вам нужно сохранить свою книгу как Macro-Enabled (.xlsm), чтобы сохранить код - Excel напомнит вам об этом на экране сохранения.
Будьте предупреждены: он будет медленнее, чем VLOOKUP, в результате необходимости просматривать весь диапазон поиска, а не останавливаться при первом найденном совпадении.
Если вы открыты для использования формулы массива вместо этого, есть способы ускорить такого рода функциональность для очень больших наборов данных ...
Различные версии, которая использует некоторые из преимуществ массива формулы для хранения значений подстановки и ускорив последующие вызовы:
' Acts like VLOOKUP in a 1-to-many scenario by concatenating all values in matching rows
' instead of just returning the first match
' Utilizes a dictionary to speedup multiple matches (great for array formulas)
Public Function VLOOKUP_MANY_ARRAY(lookup_values As Range, lookup_range As Range, column_number As Integer, Optional delimiter As Variant) As Variant
Dim vHaystack As Variant, vNeedles As Variant
Dim i As Long
Dim found As Boolean: found = False
Dim dict As Object: Set dict = CreateObject("Scripting.Dictionary")
' Set default delimiter
If IsMissing(delimiter) Then delimiter = ", "
' Get values
vHaystack = lookup_range
vNeedles = lookup_values
' If column_number is outside of the specified range, return #REF
If column_number < LBound(vHaystack, 2) Or column_number > UBound(vHaystack, 2) Then
VLOOKUP_MANY_ARRAY = CVErr(xlErrRef)
Exit Function
End If
' Add values to a lookup dictionary
For i = 1 To UBound(vHaystack, 1)
If dict.Exists(UCase(vHaystack(i, 1))) Then
dict.Item(UCase(vHaystack(i, 1))) = dict.Item(UCase(vHaystack(i, 1))) & delimiter & vHaystack(i, column_number)
Else
dict.Add UCase(vHaystack(i, 1)), vHaystack(i, column_number)
End If
Next
Dim outArr As Variant
If IsArray(vNeedles) Then ' Check number of lookup cells
' Build output array
ReDim outArr(1 To UBound(vNeedles, 1), 1 To 1) As Variant
For i = 1 To UBound(vNeedles, 1)
If dict.Exists(UCase(vNeedles(i, 1))) Then
outArr(i, 1) = dict.Item(UCase(vNeedles(i, 1)))
Else
outArr(i, 1) = CVErr(xlErrNA)
End If
Next
Else
' Single output value
If dict.Exists(UCase(vNeedles)) Then
outArr = dict.Item(UCase(vNeedles))
Else
outArr = CVErr(xlErrNA)
End If
End If
VLOOKUP_MANY_ARRAY = outArr
End Function
Это создает Dictionary
, который является специальной структурой, которая действительно хороша для поиска значений. Есть немного дополнительных накладных расходов, связанных с его строительством, но как только у вас есть структура, вы можете быстро найти в ней приложения. Это особенно хорошо с формулами массива, что в основном, когда точно та же формула попадает в целую коллекцию ячеек, то функция выполняется один раз и возвращает значения для каждой ячейки (вместо того, чтобы просто один раз, отдельно, для группы клеток). Введите его как формулу массива с CTRL + SHIFT + ENTER и сделайте первый аргумент со ссылкой на на все ваши значения поиска вместо одного.
Он будет работать без использования в качестве формулы массива, но он будет несколько медленнее, чем первая функция в этой ситуации. Однако, если вы используете его в формуле массива, вы увидите огромные ускорения.
Я так думаю, но это, вероятно, не очень.'VLOOKUP' предоставляет только одно значение, бит, если вы знаете, как максимально возможный« м »для риска, вы можете использовать' m' вложенные 'VLOOKUP'. –
Насколько важно, что это делается с помощью 'VLOOKUP'? Определенная пользователем функция VBA могла бы все это сделать, если вы захотите. – Mikegrann