На входе имею два массива ArrBase() и ArrMarker(), оба массива - строки. _ ArrBase() содержит 100500 номенклатур; _ ArrMarker() содержит 3 маркера. _ InStr() делаю поиск подстроки ArrMarker в ArrBase, если больше 0 то надо как то ставить метку ArrMarker....
Вопрос в том, что не могу понять какой Объект лучше использовать: Массивы, Коллекции или Словари, так, что бы получить две колонки : "Велосипед Apollo Aspire 20" | "Apollo" При этом, не хотелось бы выводить это все на лист в текущей книге, а сразу сохранить в CSV/XML (типа готовая структура).
Направьте плз, а то вообще сбился с пути, в голове каша Благодарю
2.3. Приложите файл(ы) с примером (общим весом не более 100 Кб) в реальной структуре и форматах данных того, что есть сейчас и того, что хотелось бы на выходе.
ОФФ
Я в завещании напишу, чтоб на урне с прахом моим выбили этот пункт. =)))
kavaka08,тот же вопрос: Если на одну номенклатуру надо поставить больше одной метки, например "Бренд:Apollo" | "Цвет:Синий" и "Бренд:Apollo" | "Цвет:Красный"
Придется создавать новый массив? Типа ArrBaseBrand(), ArrBaseColor() и т.д. Хочу понять, есть ли в VBA такой Объект для хранения значений, который можно "расширить вправо" (извиняюсь, если как то выразился не верно).
prostor написал: (Keys) - может повторятся, (Items) - должно быть уникальным
это разрыв логики какой-то. На каком этапе разработки алгоритма Вы пришли к решению, что ключи должны быть не уникальными? Совет: определите, какой нужен результат(а то сначала два столбца, теперь это может быть и 4 и 6). Нужны ли вообще проверки значений на уникальность. если нужны - зачем? Должны ли от этого зависеть значения для уникального ключа? Если да - то как? И вот тогда придет понимание как должно работать.
Даже самый простой вопрос можно превратить в огромную проблему. Достаточно не уметь формулировать вопросы...
The_Prist, Да, Вы правы. Что то меня переклинило....
Добавил файл с макросом, который делает "что надо", но не уверен что "как надо". Ниже код макроса из файла. Буду рад советам по улучшению:) Благодарю --- 1. Создаю одномерный массив ArrTmp и заполняю из диапазона в книге, чисто для примера. Поэтому эту часть можно пропустить:) 2. Все остальное ждет вашей критики:)
Код
Option Explicit
Sub MyItemMarker()
'Создаём и Наполняем Словари----------------------------------------------------
'Объявляем переменные для словарей Маркеров
Dim DictType
Dim DictBrand
Dim DictColor
Dim row As Integer ' Создаём переменную счетчик строк
Dim key As String, item As String ' Создаём переменные для Ключа и Элемента словарей
'Создаём словари
Set DictType = CreateObject("Scripting.Dictionary")
Set DictBrand = CreateObject("Scripting.Dictionary")
Set DictColor = CreateObject("Scripting.Dictionary")
' Наполняем словари из диапазона
With Sheets("test_data").Range("D3:E5") ' Словарь DictType
For row = 1 To .Rows.Count
key = CStr(.Cells(row, 1).Value) ' Получаем Key - ключ
item = CStr(.Cells(row, 2).Value) ' Получаем Item - значение
DictType.Add key, item ' Добавляем новую пару в Словарь
Next row
End With
With Sheets("test_data").Range("F3:G7") 'Словарь DictBrand
For row = 1 To .Rows.Count
key = CStr(.Cells(row, 1).Value) ' Получаем Key - ключ
item = CStr(.Cells(row, 2).Value) ' Получаем Item - значение
DictBrand.Add key, item ' Добавляем новую пару в Словарь
Next row
End With
With Sheets("test_data").Range("H3:I7") 'Словарь DictColor
For row = 1 To .Rows.Count
key = CStr(.Cells(row, 1).Value) ' Получаем Key - ключ
item = CStr(.Cells(row, 2).Value) ' Получаем Item - значение
DictColor.Add key, item ' Добавляем новую пару в Словарь
Next row
End With
'Создаём и Наполняем Результирующий Массив---------------------------------------------
Dim ArrTmp As Variant ' Временный массив
With Sheets("test_data").Range("A3", Cells(Rows.Count, 1).End(xlUp))
ArrTmp = WorksheetFunction.Transpose(.Value) ' Наполняем временный одномерный массив из диапазона
End With
Dim ArrResult() ' Результирующий массив
ReDim ArrResult(0 To UBound(ArrTmp, 1) - 1, 0 To 3) As Variant
Dim n As Long, k As Long, d As Long, sStr As String
' Переносим в массив ArrResult Наменклатуру из временного массива ArrTmp
For n = LBound(ArrResult, 1) To UBound(ArrResult, 1)
k = n + 1
ArrResult(n, 0) = ArrTmp(k)
Next n
' Заполняем массив ArrResult маркерами по Словарям
' Парсим каждый первый элемент второго уровня в массиве ArrResult
For n = LBound(ArrResult, 1) To UBound(ArrResult, 1)
' Проставляем маркер Типа намеклатуры по словарю DictType
For d = 0 To DictType.Count - 1
key = DictType.Keys()(d)
item = DictType.Items()(d)
sStr = ArrResult(n, 0)
If InStr(1, sStr, key, vbTextCompare) > 0 Then
ArrResult(n, 1) = item
End If
Next d
' Проставляем маркер Бренда намеклатуры по словарю DictBrand
For d = 0 To DictBrand.Count - 1
key = DictBrand.Keys()(d)
item = DictBrand.Items()(d)
sStr = ArrResult(n, 0)
If InStr(1, sStr, key, vbTextCompare) > 0 Then
ArrResult(n, 2) = item
End If
Next d
' Проставляем маркер Цвета намеклатуры по словарю DictColor
For d = 0 To DictColor.Count - 1
key = DictColor.Keys()(d)
item = DictColor.Items()(d)
sStr = ArrResult(n, 0)
If InStr(1, sStr, key, vbTextCompare) > 0 Then
ArrResult(n, 3) = item
End If
Next d
Next n
Stop ' Остановка по требыванию:)))
End Sub
' Наполняем словари из диапазона
With Sheets("test_data").Range("D3:E5") ' Словарь DictType
For row = 1 To .Rows.Count
key = CStr(.Cells(row, 1).Value) ' Получаем Key - ключ
item = CStr(.Cells(row, 2).Value) ' Получаем Item - значение
DictType.Add key, item ' Добавляем новую пару в Словарь
Next row
End With
With Sheets("test_data").Range("F3:G7") 'Словарь DictBrand
For row = 1 To .Rows.Count
key = CStr(.Cells(row, 1).Value) ' Получаем Key - ключ
item = CStr(.Cells(row, 2).Value) ' Получаем Item - значение
DictBrand.Add key, item ' Добавляем новую пару в Словарь
Next row
End With
With Sheets("test_data").Range("H3:I7") 'Словарь DictColor
For row = 1 To .Rows.Count
key = CStr(.Cells(row, 1).Value) ' Получаем Key - ключ
item = CStr(.Cells(row, 2).Value) ' Получаем Item - значение
DictColor.Add key, item ' Добавляем новую пару в Словарь
Next row
End With
на
Код
With Sheets("test_data").Range("D3:E5") ' Словарь DictType
For row = 1 To .Rows.Count
DictType.item(CStr(.Cells(row, 1).Value)) = CStr(.Cells(row, 2).Value)
Next row
End With
With Sheets("test_data").Range("F3:G7") 'Словарь DictBrand
For row = 1 To .Rows.Count
DictBrand.item(CStr(.Cells(row, 1).Value)) = CStr(.Cells(row, 2).Value)
Next row
End With
With Sheets("test_data").Range("H3:I7") 'Словарь DictColor
For row = 1 To .Rows.Count
DictColor.item(CStr(.Cells(row, 1).Value)) = CStr(.Cells(row, 2).Value)
Next row
End With
Это исключает ошибку при повторении ключа, без использования
Код
On Error Resume Next
"Все гениальное просто, а все простое гениально!!!"
prostor, Посмотрел файл, по моему в вашем случае использование словарей не имеет смысла, потому как у вас идет циклический перебор, а словарь подразумевает поиск по ключу, в этом преимущество словарей. и соответственно прирост в скорости
With Sheets("test_data").Range("A3", Cells(Rows.Count, 1).End(xlUp))
ArrTmp = WorksheetFunction.Transpose(.Value) ' Наполняем временный одномерный массив из диапазона
End With
Данную инструкцию не стоит использовать потому как перед
Код
Cells(Rows.Count, 1).End(xlUp)
не прописано
Код
Sheets("test_data")
и если во время выполнения макроса будет открыт другой лист, то возможна ошибка или неправильный пересчет. Я бы сделал так:
Код
With Sheets("test_data")
With .Range("A3", .Cells(Rows.Count, 1).End(xlUp))
ArrTmp = WorksheetFunction.Transpose(.Value) ' Наполняем временный одномерный массив из диапазона
End With
End With
Nordheim, по поводу актуальности исп словарей в этом макросе - я сам не уверен. Первый раз исп словари (только учусь). На что эффективней заменить словарь в данном случае? Может двумерный массив? планирую сделать наполнение Маркер:Значение из текстового файла, что б можно было исп многократно в других модулях.
В модуле 1 файла макрос работает аналогично вашему. Проверяйте! Это код макроса:
Код
Option Explicit
Sub MyItemMarker1()
Dim DictType()
Dim n&, k As Byte, i As Byte
Dim ArrResult()
DictType = Application.Transpose(Sheets("test_data").Range("D3:F7").Value)
With Sheets("test_data")
With .Range("A3", .Cells(Rows.Count, 1).End(xlUp))
ArrResult() = .Value
End With
End With
ReDim Preserve ArrResult(1 To UBound(ArrResult), 1 To 4)
For n = LBound(ArrResult, 1) To UBound(ArrResult, 1)
For k = LBound(DictType, 1) To UBound(DictType, 1)
For i = LBound(DictType, 2) To UBound(DictType, 2)
If Not IsEmpty(DictType(k, i)) Then
If InStr(1, ArrResult(n, 1), DictType(k, i), vbTextCompare) > 0 Then ArrResult(n, k + 1) = DictType(k, i)
End If
Next i, k, n
Range("h1").Resize(UBound(ArrResult, 1), UBound(ArrResult, 2)) = ArrResult
Stop
End Sub
Option Explicit
Sub MyItemMarker1()
Dim DictType()
Dim n&, k As Byte, i As Byte
Dim ArrResult()
DictType = Application.Transpose(Sheets("test_data").Range("D3:F7").Value)
ArrResult() = Sheets("test_data").Range("A3", Sheets("test_data").Cells(Rows.Count, 1).End(xlUp)).Value
ReDim Preserve ArrResult(1 To UBound(ArrResult), 1 To 4)
For n = LBound(ArrResult, 1) To UBound(ArrResult, 1)
For k = LBound(DictType, 1) To UBound(DictType, 1)
For i = LBound(DictType, 2) To UBound(DictType, 2)
If Not IsEmpty(DictType(k, i)) Then
If InStr(1, ArrResult(n, 1), DictType(k, i), vbTextCompare) > 0 Then ArrResult(n, k + 1) = DictType(k, i)
End If
Next i, k, n
Stop
End Sub
Nordheim написал: Данную инструкцию не стоит использовать потому как
есть небольшое уточнение- Rows.Count тоже будет браться не от листа Sheets("test_data"), а от активного листа. В данном коде это не важно, т.к. книга используется одна (да и лист тоже всего один), но бывают ситуации когда в работе участвует несколько книг, и не факт что они все одного вида.
Сорри, не смог ответить сразу. Код супер! Еще раз убеждаюсь, что не достаточно знать только синтаксис в программировании, а и уметь мыслить "глубоко" Спасибо за помощь! --- В последнем примере вы исп только массивы, без словарей. Массив DictType наполняется только "ключами", а значение опустили. В конкретном случае это оправдано. Интересует момент такой: если потребуется все таки использовать пару "ключ:значение" - то это только Словари?
Возможна такая ситуация, когда исходная строка может содержать разные обозначения цвета, а метку надо поставить всем одинаковую, например: "красн:Красный" или "red:Красный" или "#FF0000:Красный"
При использовании словарей желательно что бы массив содержал значения равные ключам, в этом случае будет производиться поиск значения в списке ключей и возвращать элемент принадлежащий ключу. пример: в словаре DicObj под индексом №1 Key = "Test", Item = "Пример", Массив MyArr(1,1) = "Test" MyArray(1,2) = "Empty"
Код
MyArray(1,2) = DicObj.Item(Cstr(MyArray(1,1))
В приведенном примере части массива MyArray(1,2) будет присвоено значение "Пример" без всякого перебора циклом. Это случай который мне известен как преимущество словаря перед массивами.
"Все гениальное просто, а все простое гениально!!!"
prostor написал: если потребуется все таки использовать пару "ключ:значение" - то это только Словари?
Есть ВСТРОЕННЫЙ инструмент VBA - Коллекции (Collection). Без необходимости подключения внешних библиотек. Несомненным плюсом является возможность указания порядка добавления пары (ключ-значение) (Before/After), что упрощает (при прочих равных) сортировку. Не помню где 'стянул' это файл и кто автор