Доброго времени суток ! Почему-то не создается массив из диапазона(( Делаю данную операцию первый раз, поэтому скорее всего ошибка в синтаксисе. Но не могу найти ! Помогите, пожалуйста ! Текст макроса прикреплен, а также приведен ниже:
[vba]
Код
Option Explicit Public OstFile As Workbook, gFirma$, gAdr As String, ID As Integer Private Dinamyc As Workbook, DinamycFileName$, PatternRecFileName As String, Lr1&, Lr2&, Lr3 As Long, _ PatternRecom As Workbook, i&, j As Long Dim NameOfEGAIS() As Variant, NameOfPattern() As Variant, ProdName As String
Sub AnalisOst() Set OstFile = ThisWorkbook 'UserForm1.Show 'форма. Работает ID = 30 OstFile.Worksheets(1).Activate Lr1 = OstFile.Worksheets(1).Cells(Rows.Count, "B").End(xlUp).Row DinamycFileName = OstFile.Path & "\dinamika_prodazh" & ID & ".xls" Set Dinamyc = Workbooks.Open(DinamycFileName) Lr2 = Dinamyc.Worksheets(1).Cells(Rows.Count, "C").End(xlUp).Row [color=blue]'в Debug Lr2=5, все верно[/color]
'перенос наименований товара и заполнение массива из ЕГАИС NameOfEGAIS = Dinamyc.Worksheets(1).Range(Cells(2, 3), Cells(Lr2, 3)).Value[b] [color=red]' в массив ничего не записывается !!![/b][/color] Debug.Print LBound(NameOfEGAIS), NameOfEGAIS(0) [b][color=red]' тут выдает ошибку Subscript out of range и LBound=1[/color][/b]
Terminate_Sub: Dinamyc.Close SaveChanges:=False Application.CutCopyMode = False Cells(3, 3).Select End Sub
[/vba]
Доброго времени суток ! Почему-то не создается массив из диапазона(( Делаю данную операцию первый раз, поэтому скорее всего ошибка в синтаксисе. Но не могу найти ! Помогите, пожалуйста ! Текст макроса прикреплен, а также приведен ниже:
[vba]
Код
Option Explicit Public OstFile As Workbook, gFirma$, gAdr As String, ID As Integer Private Dinamyc As Workbook, DinamycFileName$, PatternRecFileName As String, Lr1&, Lr2&, Lr3 As Long, _ PatternRecom As Workbook, i&, j As Long Dim NameOfEGAIS() As Variant, NameOfPattern() As Variant, ProdName As String
Sub AnalisOst() Set OstFile = ThisWorkbook 'UserForm1.Show 'форма. Работает ID = 30 OstFile.Worksheets(1).Activate Lr1 = OstFile.Worksheets(1).Cells(Rows.Count, "B").End(xlUp).Row DinamycFileName = OstFile.Path & "\dinamika_prodazh" & ID & ".xls" Set Dinamyc = Workbooks.Open(DinamycFileName) Lr2 = Dinamyc.Worksheets(1).Cells(Rows.Count, "C").End(xlUp).Row [color=blue]'в Debug Lr2=5, все верно[/color]
'перенос наименований товара и заполнение массива из ЕГАИС NameOfEGAIS = Dinamyc.Worksheets(1).Range(Cells(2, 3), Cells(Lr2, 3)).Value[b] [color=red]' в массив ничего не записывается !!![/b][/color] Debug.Print LBound(NameOfEGAIS), NameOfEGAIS(0) [b][color=red]' тут выдает ошибку Subscript out of range и LBound=1[/color][/b]
Откуда такой вывод? Всё записывается - четыре элемента в столбик. Включите перед выполнением наблюдение за переменной NameOfEGAIS - по верхнему меню редактора VBA командой Debug \ Add Watch. Поставьте точку останова на следующую строку за чтением массива и всё увидите в Окне наблюдения (Watches).
LBound=1 - всё правильно, это же нижняя граница. Чтобы верхнюю получить надо функцию UBound использовать. Вы случайно не на этом основании делаете вывод о пустоте массива? Ошибка же "за пределами массива" возникает из-за обращения к несуществующему элементу массива NameOfEGAIS(0). Дело в том, что массивы, считанные из диапазона рабочего листа, всегда двумерные и нумерация их строк и столбцов всегда начинается с 1 (даже если в программе явно установлено Option Base 0). И адресация к элементу такого массива тоже всегда двумерная: даже если массив состоит только из одной ячейки, то адрес ее в массиве будет NameOfEGAIS(1, 1).
Полностью задачу пока не очень понимаю, поэтому начнём с малого - с красного текста.
Откуда такой вывод? Всё записывается - четыре элемента в столбик. Включите перед выполнением наблюдение за переменной NameOfEGAIS - по верхнему меню редактора VBA командой Debug \ Add Watch. Поставьте точку останова на следующую строку за чтением массива и всё увидите в Окне наблюдения (Watches).
LBound=1 - всё правильно, это же нижняя граница. Чтобы верхнюю получить надо функцию UBound использовать. Вы случайно не на этом основании делаете вывод о пустоте массива? Ошибка же "за пределами массива" возникает из-за обращения к несуществующему элементу массива NameOfEGAIS(0). Дело в том, что массивы, считанные из диапазона рабочего листа, всегда двумерные и нумерация их строк и столбцов всегда начинается с 1 (даже если в программе явно установлено Option Base 0). И адресация к элементу такого массива тоже всегда двумерная: даже если массив состоит только из одной ячейки, то адрес ее в массиве будет NameOfEGAIS(1, 1).Gustav
Gustav, вы мне просто пелену с глаз убрали !))) Я вчера поздно ночью уже впал в ступор))). Конечно, вы правы. Все заработало ! Насчет LBound - это конечно я ошибся, по аналогии с переменной Lr (Last Row) буква L у меня ассоциировалась с концом списка ). Окном Add Watch активно пользуюсь, но почему то решил, что массив оно вывести не в состоянии, и даже не попробовал)). Насчет двумерной нумерации не знал, так что тут для меня открылась новая информация, благодаря вам ! А полностью задачу не поняли, потому что я поудалял лишний код, чтоб не морочить вам голову, а оставил только тот фрагмент, который выдавал ошибку. Спасибо вам большое !
По дальнейшей цели создания этих массивов: есть два списка наименований (примерно по 1т в каждом, но не одинаковое кол-во), нужно сравнить все элементы 1го списка со вторым и несовпадающие добавить в конец 2го списка (поэтому 2й список при запуске программы явно может быть больше). Я после выгрузки этих списков в массивы дальше перебираю их циклом For Next, сравнивая каждый элемент 1го списка с каждым элементом 2го. Не очень оптимально, но зато все ясно и прозрачно. Но долго. Есть ли какой-то более продвинутый функционал для решения этой задачи ? Может, надо не в массивы загрузить списки, а в словари и потом использовать функцию Filter (ни разу еще это не делал) ? Читал, что в словарях какой-то алгоритм бинарного поиска очень шустрый.. Или использовать функцию WorksheetFunction.Match ? В каком направлении двигаться ?
Gustav, вы мне просто пелену с глаз убрали !))) Я вчера поздно ночью уже впал в ступор))). Конечно, вы правы. Все заработало ! Насчет LBound - это конечно я ошибся, по аналогии с переменной Lr (Last Row) буква L у меня ассоциировалась с концом списка ). Окном Add Watch активно пользуюсь, но почему то решил, что массив оно вывести не в состоянии, и даже не попробовал)). Насчет двумерной нумерации не знал, так что тут для меня открылась новая информация, благодаря вам ! А полностью задачу не поняли, потому что я поудалял лишний код, чтоб не морочить вам голову, а оставил только тот фрагмент, который выдавал ошибку. Спасибо вам большое !
По дальнейшей цели создания этих массивов: есть два списка наименований (примерно по 1т в каждом, но не одинаковое кол-во), нужно сравнить все элементы 1го списка со вторым и несовпадающие добавить в конец 2го списка (поэтому 2й список при запуске программы явно может быть больше). Я после выгрузки этих списков в массивы дальше перебираю их циклом For Next, сравнивая каждый элемент 1го списка с каждым элементом 2го. Не очень оптимально, но зато все ясно и прозрачно. Но долго. Есть ли какой-то более продвинутый функционал для решения этой задачи ? Может, надо не в массивы загрузить списки, а в словари и потом использовать функцию Filter (ни разу еще это не делал) ? Читал, что в словарях какой-то алгоритм бинарного поиска очень шустрый.. Или использовать функцию WorksheetFunction.Match ? В каком направлении двигаться ?Serg5876
Сергей
Сообщение отредактировал Serg5876 - Воскресенье, 28.01.2024, 12:08
Читал, что в словарях какой-то алгоритм бинарного поиска очень шустрый.. Или использовать функцию WorksheetFunction.Match ? В каком направлении двигаться ?
Да, наверное, эффективнее всего для решения поставленной задачи здесь использовать объект "Словарь" (Scripting.Dictionary). Без всяких утомительных попарных сравнений элементов двух массивов. Сначала записываете в словарь элементы массива 2 (циклом по этому массиву). А затем, тоже циклом, добавляете в словарь элементы массива 1. При этом, если очередного элемента массива 1 еще нет в словаре, он добавляется в конец словаря, иначе - просто игнорируется. По окончании процесса имеете словарь, содержащий все уникальные элементы обоих массивов.
Теоретически хорошо бы еще и сортировку по алфавиту к элементам словаря применить, чтобы получился классический отсортированный "справочник" уникальных элементов. Но если сортировка нужна только для ускорения доступа к элементам (как это было бы уместно для списка на рабочем листе), то для этого в словаре существует механизм доступа по ключам, а также быстрая проверка наличия того или иного значения. Поэтому фактическая последовательность элементов внутри словаря не столь уж и важна, и, соответственно, необходимость сортировки - не столь уж актуальна.
Читал, что в словарях какой-то алгоритм бинарного поиска очень шустрый.. Или использовать функцию WorksheetFunction.Match ? В каком направлении двигаться ?
Да, наверное, эффективнее всего для решения поставленной задачи здесь использовать объект "Словарь" (Scripting.Dictionary). Без всяких утомительных попарных сравнений элементов двух массивов. Сначала записываете в словарь элементы массива 2 (циклом по этому массиву). А затем, тоже циклом, добавляете в словарь элементы массива 1. При этом, если очередного элемента массива 1 еще нет в словаре, он добавляется в конец словаря, иначе - просто игнорируется. По окончании процесса имеете словарь, содержащий все уникальные элементы обоих массивов.
Теоретически хорошо бы еще и сортировку по алфавиту к элементам словаря применить, чтобы получился классический отсортированный "справочник" уникальных элементов. Но если сортировка нужна только для ускорения доступа к элементам (как это было бы уместно для списка на рабочем листе), то для этого в словаре существует механизм доступа по ключам, а также быстрая проверка наличия того или иного значения. Поэтому фактическая последовательность элементов внутри словаря не столь уж и важна, и, соответственно, необходимость сортировки - не столь уж актуальна.Gustav
Доброго дня всем ! Особенно Gustavu) С вашей помощью моя программа-макрос прекрасно работала... до тех пор, пока не возник частный случай: при записи диапазона в массив размер диапазона - одна ячейка. И все рухнуло ! Размер диапазона - это список адресов торговых точек из листа Excel, которые пользователь выбирает из выпадающего списка ComboBox. Так вот, в одном случае торговая точка всего одна оказалась.. Макрос выдает ошибку на этапе формирования списка для ComboBox (скрин прикреплен). Ошибка происходит вот в этой форме:
[vba]
Код
Private Sub ComboBox1_Change() Dim AdrMarket() As Variant
Firma = Me.ComboBox1.Text Me.Label1.Caption = lbl1captionBegin & Firma
FirmCol = AdrPoint.Cells.Find(Firma).Column LastRow = AdrPoint.Cells(Rows.Count, FirmCol).End(xlUp).Row AdrPoint.Activate AdrMarket = Range(Cells(3, FirmCol), Cells(LastRow, FirmCol)).Value ' [color=red]вот здесь, при записи диапазона в динамический массив. При длине диапазона =1 происходит ошибка.[/color] Me.ComboBox2.List = AdrMarket End Sub
[/vba]
Вопрос: Бывает ли диапазон Range из одного элемента ? Можно ли свойством List заполнить список из одного элемента ? Или надо в таком случае добавлять специальный признак конца списка (2ю строчку) и потом отлавливать, чтоб его пользователь не выбирал ?
Доброго дня всем ! Особенно Gustavu) С вашей помощью моя программа-макрос прекрасно работала... до тех пор, пока не возник частный случай: при записи диапазона в массив размер диапазона - одна ячейка. И все рухнуло ! Размер диапазона - это список адресов торговых точек из листа Excel, которые пользователь выбирает из выпадающего списка ComboBox. Так вот, в одном случае торговая точка всего одна оказалась.. Макрос выдает ошибку на этапе формирования списка для ComboBox (скрин прикреплен). Ошибка происходит вот в этой форме:
[vba]
Код
Private Sub ComboBox1_Change() Dim AdrMarket() As Variant
Firma = Me.ComboBox1.Text Me.Label1.Caption = lbl1captionBegin & Firma
FirmCol = AdrPoint.Cells.Find(Firma).Column LastRow = AdrPoint.Cells(Rows.Count, FirmCol).End(xlUp).Row AdrPoint.Activate AdrMarket = Range(Cells(3, FirmCol), Cells(LastRow, FirmCol)).Value ' [color=red]вот здесь, при записи диапазона в динамический массив. При длине диапазона =1 происходит ошибка.[/color] Me.ComboBox2.List = AdrMarket End Sub
[/vba]
Вопрос: Бывает ли диапазон Range из одного элемента ? Можно ли свойством List заполнить список из одного элемента ? Или надо в таком случае добавлять специальный признак конца списка (2ю строчку) и потом отлавливать, чтоб его пользователь не выбирал ?Serg5876
Gustav, спасибо, все заработало ! Range с одним элементом сработал. Ошибку выдавал List. Теперь я узнал, что свойством List нельзя заполнить 1 элемент)). А также познакомился с функцией IsArray, тоже до этого не приходилось использовать. А то я начал мудрить со специальным значением (признак конца списка), за которым бы потом пришлось следить, чтобы его не выбирали из списка))
Gustav, спасибо, все заработало ! Range с одним элементом сработал. Ошибку выдавал List. Теперь я узнал, что свойством List нельзя заполнить 1 элемент)). А также познакомился с функцией IsArray, тоже до этого не приходилось использовать. А то я начал мудрить со специальным значением (признак конца списка), за которым бы потом пришлось следить, чтобы его не выбирали из списка))Serg5876
Сергей
Сообщение отредактировал Serg5876 - Понедельник, 18.03.2024, 18:57