VBA/Excel — Подсчет уникальных слов в столбцах с несколькими словами в каждой ячейке

#excel #vba #unique

Вопрос:

Я работаю с нижеприведенным набором данных. Для каждой компании я хотел бы понять, сколько разных продуктов они заказывают.

Например: компания » ААА » заказывает 6 различных продуктов (Продукт 1,2,3,4,5,7).

Пример

Не уверен, нужно ли нам разбивать слова в каждом столбце, а затем считать по одному в цикле, или есть какой-нибудь более быстрый метод? Здесь я должен использовать VBA, а мой набор данных превышает 100 тыс.

Комментарии:

1. Вам нужно только посчитать их? Не показывая, какие продукты он тоже заказывал ?

2. Да, только уникальное количество

3. Ваш уточняющий ответ пришел немного позже. Тем временем я опубликовал фрагмент кода, возвращающий уникальное имя клиента, за которым следует количество заказанных продуктов и название каждого заказанного продукта в следующих столбцах. Я (только) подумал, что это будет более полезно. Пожалуйста, попробуйте. В противном случае код может быть намного проще… Он возвращается на другом листе. Его можно легко адаптировать для возврата на том же листе, если это то, что вам нужно.

Ответ №1:

Вы могли бы, возможно, собрать что-то воедино, используя, предполагая, что данные в A1:C? :

 Sub Test()  Dim arr As Variant Dim lr As Long, x As Long, y As Long Dim dict1 As Object: Set dict1 = CreateObject("Scripting.Dictionary") Dim dict2 As Object: Set dict2 = CreateObject("Scripting.Dictionary")  'Get initial array (NOTE: implicit reference to the active worksheet) lr = Cells(Rows.Count, "A").End(xlUp).Row arr = Range("A2:C" amp; lr)  'Loop through array and fill dictionary For x = LBound(arr) To UBound(arr)  dict1(arr(x, 1)) = dict1(arr(x, 1)) amp; "," amp; arr(x, 3) Next  'Loop through dictionary and count unique items For y = 0 To dict1.Count - 1  For Each el In Split(dict1.Items()(y), ",")  dict2(el) = 1  Next  dict1(dict1.keys()(y)) = dict2.Count - 1  dict2.RemoveAll    'Check the result  Debug.Print dict1.keys()(y) amp; "-" amp; dict1.Items()(y) Next  End sub  

Комментарии:

1. Очень элегантное решение. Это тоже должно быть довольно быстро.

2. Это здорово — большое спасибо

Ответ №2:

Пожалуйста, протестируйте следующий код. Он вернет (в приведенном выше коде на следующем листе, но может вернуть на любом листе) уникального клиента, за которым следует общее количество продуктов, а в следующих столбцах-заказанные продукты:

 Sub ProductsPerClient()  Dim sh As Worksheet, sh1 As Worksheet, lastR As Long, arr, arrSpl, arrFin, colMax As Long  Dim i As Long, j As Long, dict As Object    Set sh = ActiveSheet  Set sh1 = sh.Next 'use here the sheet you need  lastR = sh.Range("A" amp; sh.rows.count).End(xlUp).row  arr = sh.Range("A2:C" amp; lastR).value  Set dict = CreateObject("Scripting.Dictionary")  For i = 1 To UBound(arr)  arrSpl = Split(Trim(arr(i, 3)), ",")  If Not dict.Exists(arr(i, 1)) Then  dict.Add arr(i, 1), Join(arrSpl, "|")  If UBound(arrSpl)   1 gt; colMax Then colMax = UBound(arrSpl)   1  Else  dict(arr(i, 1)) = dict(arr(i, 1)) amp; "|" amp; Join(arrSpl, "|")  If UBound(Split(dict(arr(i, 1)), "|"))   1 gt; colMax Then colMax = UBound(Split(dict(arr(i, 1)), "|"))   1  End If  Next i  ReDim arrFin(1 To dict.count, 1 To colMax   2)   For i = 0 To dict.count - 1  arrFin(i   1, 1) = dict.Keys()(i)  arrSpl = Split(dict.items()(i), "|")  arrFin(i   1, 2) = UBound(arrSpl)   1  For j = 0 To UBound(arrSpl)  arrFin(i   1, j   3) = arrSpl(j)  Next j  Next i  'drop the final array content:  sh1.Range("A2").Resize(UBound(arrFin), UBound(arrFin, 2)).value = arrFin  End Sub  

Ответ №3:

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

 =SEARCH(",",C2,1) 1  

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

Комментарии:

1. Я думаю, что это другое, в вашем случае мы будем считать все продукты, и нам нужно количество уникальных продуктов. Например, в вашем случае Product_7 будет дублироваться

2. @Лоэнгрин: спасибо за ваше замечание. Когда я писал свой ответ, еще не было ясно, нужны ли уникальные записи. Тем не менее я хотел бы сохранить свой ответ по ссылочным соображениям (вы никогда не знаете, что у человека есть подобный вопрос без уникального условия, которому мог бы помочь этот ответ).