Друзья, на VBA писать только начинаю, пока не разобрался, но голову ломаю несколько дней
Мне необходимо производить манипуляции с таблицей данных, где в строках некий набор записей, а в столбцах различные подзаписи (типа "продавец", "продукт", "цена"...), то есть налицо двумерный массив. Очень хочется обращаться с этим массивом, как с ассоциативным. Примерно так
Таким образом к элементам массива удобно обращаться по ключам, складывать, вычитать и тд. Наверняка в VBA есть решение, но для меня оно не открывается.
Что я изучил: Collection, scripting.dictionary - не подходит, поскольку на один ключ там только одно значение (если я всё правильно понял) Пользовательский тип данных - не подходит, поскольку набор колонок может меняться от раза к разу (как задавать тип данных динамически, я не нашёл)
Что приходит на ум: 1. Создать двумерный массив (просто скопировать таблицу в массив) вместе с названиями столбцов. Таким образом в первой строке массива у меня будет массив с названиями полей. И когда мне нужно будет обратиться к элементу a[345876]["Продукт"], то я буду искать в первой строке порядковый номер элемента с названием "Продукт" примерно так
Код
for i=1 to a[1].Count
if aa == "Продукт" then exit For
Next' a[345876][i] ' будет искомым элементом двумерного массива
2. Создать коллекцию массивов и проделать примерно тоже самое. Чем это лучше или хуже не знаю, то мне кажется, это будет одно и тоже. 3. Создать отдельную коллекцию типа ColNames(value='номер элемента' key='имя колонки'). Тогда к элементу a[345876]["Продукт"] можно будет обратиться таким образом a[345876][ColNames.Item("Продукт" ]
Но всё это, как мне кажется, кривые способы. Наверняка, есть красивое решение для такого рода задач.
Как вообще выглядит моя задача, точнее её часть: 1.У меня есть таблица, которую я копирую из другого файла. Строк в таблице десятки тысяч, столбцов - десятки (количество столбцов и их названия могут меняться от раза к разу) Таблица примерно такого вида
Клиент
продукт
объём
штуки
Сумма
k003382
pr098782
45
-20
94.4
k084982
pr98376
98
87
-9837
k084982
pr98346
-34
874.2
-35
k084876
pr98346
45
7636
7736
2.Я формирую из комбинации значений нескольких столбцов столбец с ключом, который пока не является уникальным. 3. сортирую таблицу по пока не уникальному ключу 4. формирую массив уникальных ключей (убираю дубликаты) 5. далее нужно суммировать числовые столбцы по уникальному ключу. (это вполне решается прописыванием формул типа суммесли(...), но считает такой объем данных очень долго. 6. дальше нужно будет производить другие операции, но это уже другая история.
Возможно есть способ одновременного формирования списка уникальных ключей и суммирования строк с повторными ключами. Пока я формирую список ключей просто через .RemoveDuplicates
И так финальные вопросы: 1. Как создать такую структуру данных (массив, коллекцию... что угодно), чтобы можно было обращаться по принципу двухмерного ассоциативного массива. 2. Как удалить дубликаты в столбце "A" одновременным суммированием числовых значений в столбцах "D", "E"... там где значения столбца А повторяются.
Буду признателен за любые советы и конструктивную критику
1) файлик приложите. 2) элементы коллекций и словарей могут иметь любые типы - в т.ч. массивы, структуры, словари и коллекции. 3) хотя бы примерный список того, зачем вам это надо - можете сформулировать?
upd а, ну и ООП ещё существует, говорят upd-2 о!!! еще умное слово вспомнил - SQL. правда, насчет изменения (UPDATE/INSERT/DELETE) не уверен (не специалист), но, возможно, вам и SELECT'ов хватит? upd-3 а еще в эксе есть сводные таблицы, и, особенно в последних версиях, достаточно мощные средства обработки больших массивов данных - OLAP, срезы и т.п....
в общем, понятно? умных слов много, но всё идёт от задачи - пути, способы, инструменты. а задачи пока не видно (имхо).
1. файлик приложил На листе1 - начиная со столбца B - таблица в том виде как я её импортирую из исходного файла. Столбец А - это ключ, который нужно сделать уникальным и по которому просуммировать. 2. то что элементом коллекции может быть массив это я понял, но я пока не смог придумать структуру данных чтобы с ней удобно было обращаться. 3. Зачем мне нужно обращаться с таблицей как двумерным массивом. У меня есть ещё некий "файл связи", в котором заданы правила преобразования числовых показателей, которые есть в исходной таблице в файле связи примерно такой набор данных param1 val param2 val param3 col param4 val param5 col ... Что означате, что нужно сформировать новые числовые показатели val и col. val = param1 + param2 + param4 col = param3 + param5...
Соответственно, чтобы обращаться к данным в исходной таблице и суммировать их в показатели другой системы координат, мне удобно к ним обращаться ассоциативно типа a[key1][param1] + a[key1][param2]..., а не высчитывать и не вводить какие-то индексы, которые потом интерпретировать и тд.
upd а, ну и ООП ещё существует, говорят upd-2 о!!! еще умное слово вспомнил - SQL... upd-3 а еще в эксе есть сводные таблицы...
1. По поводу ООП, я не спец по VBA. Я знаю как задать пользовательский тип данных, но я не знаю как его менять автоматически в зависимости от входного файла. В одном случае мне может понадобиться 30 переменных в объекте, в другой 40. Если можно менять типы данных динамически или есть ещё какие-то решения, то буду признателен за ликбез. 2. По поводу SQL. Средствами SQL моя задача решалась бы очень просто. Но мы не ищем лёгких путей Считаем, что Access-а у меня нет, у потенциального пользователя тоже. Как обращаться к таблице при помощи SQL запросов без БД? Если это возможно, то это будет супер 3. Сводные таблицы. Я пробовал, у меня не получилось. Загвоздка в том, что мне нужно просуммировать несколько столбцов. Я понял как в сводной таблице просуммировать один числовой столбец с учётом дублирования в ключевом столбце, считает отлично. А вот как просуммировать таким образом 30 столбцов, я не понял. Но я честно говоря в сводных таблицах пока слабоват.
Alex пишет: 2. По поводу SQL. Средствами SQL моя задача решалась бы очень просто. Но мы не ищем лёгких путей:) Считаем, что Access-а у меня нет, у потенциального пользователя тоже. Как обращаться к таблице при помощи SQL запросов без БД? Если это возможно, то это будет супер
на память не напишу - пользуюсь редко. но драйвер ODBC может работать и с экселевскими таблицами. и с dbf-ками, и даже с текстовыми файлами. для начала курим тему от разработчика: http://support.microsoft.com/kb/257819/ru (ссылка на страницу, машинно-переведенную; если у вас всё в порядке с английским - лучше переключиться на оригинал)
фрилансер Excel, VBA - контакты в профиле "Совершенствоваться не обязательно. Выживание — дело добровольное." Э.Деминг
ikki, Михаил С., ваши намёки про сводные таблицы уже дали результаты, я понял куда копать и, кажется, разобрался как просуммировать по разным столбцам. Думаю, что просуммировать и получить список уникальных ключей я смогу теперь. Спасибо! Ваши мысли мне очень помогли копать в нужном направлении
Остался вопрос с двумерным ассоциативным массивом. Как организовать такую двухмерную структуру данных, которым будет удобно обращаться.
upd: Начал читать, кажется, там есть кажется там есть возможность обращаться к таблице на языка SQL. Надеюсь для этого не нужны будут какие-то дополнительные модули офисные, которых может не быть у потенциального пользователя.
Что означате, что нужно сформировать новые числовые показатели val и col. val = param1 + param2 + param4 col = param3 + param5...
Ну это я к примеру так написал Файл связи будет выглядеть примерно так (см. приложение) Этот файл задаёт правила формирования новых числовых показателей. В столбце "В" перечислены новые показатели, в столбце "А" - показатели из исходной таблицы. Если показателю из столбца "В" соответствует несколько показателей из столбца "А", то эти показатели в исходной таблице нужно суммировать, чтобы получить новый показатель. Такая задача преобразования. Может она тоже как-то просто решается без всяких заморочек, но я пока не нашёл как.
ага... т.е. в исходной таблице у вас может быть разное кол-во столбцов (с показателями) и каждый из показателей приндлежит какой-либо группе... и вам нужны суммы именно по группам. но в разрезе покупателей-продуктов? да?
гм. ну тогда у вас первая таблица ненормализованная и непосредственно сводной... я не знаю, может быть, в последних версиях экса есть что покруче... но в моей версии (2003-й) понадобится предварительная обработка по нормализации.
и вообще я понимаю, что это "например". но, имхо, какой-то небрежный. вот у вас в таблице заголовки
Volume (Piece)
GSV
Order Quantity
Off Invoice
Centralised delivery
Centralised delivery
последние два заголовка одинаковые - это нормально? не для каждого заголовка есть соответствующее значение во второй таблице - это что? есть "похожие" значения - с "припиской" on invoice а для первого элемента ("Volume (Piece)") я вообще ничего не нашёл или он общий и не входит в "группируемые"?
задачка более-менее интересная, но столько вопросов...
фрилансер Excel, VBA - контакты в профиле "Совершенствоваться не обязательно. Выживание — дело добровольное." Э.Деминг
Я так делал словари в словаре - думаю так код проще и короче:
Код
Sub PereborFailov2() ' словарь в словаре
Dim a, i&, t$, Dic As Object, Dic2 As Object
Dim el, col
a = Range("C3", Cells(Rows.Count, "A").End(xlUp)).Value
Set Dic = CreateObject("Scripting.Dictionary")
With Dic
.CompareMode = 1
For i = 1 To UBound(a)
t = a(i, 1)
If Not .exists(t) Then .Add t, CreateObject("Scripting.Dictionary")
.Item(t).Item(a(i, 2) & "|" & a(i, 3) & "|" & i) = 0&
Next
End With
For Each el In Dic.keys
Debug.Print "Открываем файл " & el
Set Dic2 = Dic.Item(el)
For Each col In Dic2.keys
Debug.Print "Ищем данные " & col '& "|" & Dic2.Item(col)
Next
Debug.Print "Закрываем файл " & el
Next
End Sub
Суть в одной строке - если ключа нет, добавляем его с словарём в Item. Затем в следующей строке дополняем словарь словаря - он в любом случае уже есть.
Задачу/файлы не смотрел, но кажется, что словари тут бы пригодились...
Михаил С. пишет: Alex, ваша задача как раз для сводных таблиц.
Михаил С. Спасибо за наводку на правильный путь.
Цитата
ikki пишет: для очистки совести:
Цитата
...понадобится предварительная обработка по нормализации.
пример во вложении. запускаете макрос - Лист2 заполнится данными в виде, пригодном для сводной. сводная делается в три щелчка
Цитата
...но столько вопросов...
сделал как понял надеюсь, разберетесь
ikki спасибо большое за такую оперативную готовность помочь не только словом, но и делом. Макрос конечно делает не совсем то что нужно, но это просто я так криво задачу, видимо, описал. Но логику я понял, это как раз то от чего я хотел уйти. Вы там просто переименовываете столбцы... В общем это не совсем ассоциативная логика. Но в сводных таблицах похоже можно обращаться по именам полей, мне кажется я найду в этом решение.
Цитата
R Dmitry пишет:
Цитата
Alex пишет: 2. По поводу SQL. Средствами SQL моя задача решалась бы очень просто.
Вот самый простейший пример, изучайте
R Dmitry Спасибо большое. Я потратил пару часов, чтобы понять подключены у меня драйвера ODBC или ещё что-то, а с вашим примером я быстро понял, что всё у меня работает. Способ отличный! Сейчас я похоже обойдусь сводными таблицами, но на будущее, я обязательно запомню.
Как допишу, отпишусь, как в итоге решил свою задачу. Ещё раз все спасибо, честно, не ожидал такой мощной поддержки, был приятно удивлён! Всем удачи