Возникла нерешаемая проблема с преобразованием данных в список.
Формируется отчет по закупкам из 1С, в виде готовой сводной таблицы, со 150000 строками, их необходимо преобразовать в плоскую таблицу для дальнейшей работы.
По настройкам в 1С ничего не нашел, в программировании VBA пока не разбираюсь (обещаю исправиться), вручную долго, отчеты иногда формирую в течение всего дня, копируя и вставляя данные в столбцы.
А где таблица на входе и таблица на выходе? В вашем примере несколько заполненных строк и всё.
Мастерство программиста не в том, чтобы писать программы, работающие без ошибок. А в том, чтобы писать программы, работающие при любом количестве ошибок.
Мотя, соглашусь, что вместо того чтоб исправлять данные, надо их не каверкать, но есть два варианта, или указанное не проделать, или это более трудоемко, чем переработать. Вот тогда на помощь приходит Excel.
Судя по всему, Askabara, регулярно делает экспорт из 1С. Полагаю, это - его ежедневная (еженедельная / ежемесячная работа). Значит, это работа должна быть доведена до "автоматизма", чтобы быть всегда успешно выполненной. Я - сторонник минимальных телодвижений, если условия работы это позволяют. А также - сторонник исключения "рукопашной" работы пользователя.
Да, отчеты приходится выгружать ежедневно, и мне хотелось бы минимизировать человеческий фактор. По той инструкции я пробовал формировать отчет, но ничего из этого у меня не получилось, потому что данные находятся в папках, названия брендов/типы/категории никак не систематизированы в базе, из-за чего при формировании плоской таблицы выходит лишь список артикулов без привязки и указания иерархии. Изначально таблица формируется в виде сводной таблицы с группировкой данных, может быть есть способы, с помощью которых получится имеющуюся группировку каким-то образом разбить по столбцам? Строк больше 150000, из-за ограничений форума выложил лишь маленькую часть имеющихся данных. Было бы хорошо, если хотя бы подсказали, в каком направлении двигаться) Как я понял, без кода мне тут никак мне не справиться...
На словаре с коллекцией, строго под строение примера, т.е. на 5 уровней!
Код
Option Explicit
Sub tt()
Dim c As Range
Dim t0$, t1$, t2$, t3$, t$
Dim d As Object, k, el, i&
Set d = CreateObject("Scripting.Dictionary"): d.comparemode = 1
For Each c In [b10].CurrentRegion.Columns(1).Cells
Select Case c.IndentLevel
Case 0: t0 = c.Value: t1 = Empty: t2 = Empty: t3 = Empty: t = Empty
Case 1: t1 = c.Value
Case 2: t2 = c.Value
Case 3: t3 = c.Value
Case 4
t = t0 & "|" & t1 & "|" & t2 & "|" & t3
If Not d.exists(t) Then d.Add t, New Collection
d.Item(t).Add c.Value
End Select
Next
If d.Count Then
Application.ScreenUpdating = False
With Workbooks.Add(1).Sheets(1)
For Each k In d.keys
For Each el In d.Item(k)
i = i + 1
.Cells(i, 1).Resize(, 4) = Split(k, "|")
.Cells(i, 5) = el
Next
Next
.Columns.AutoFit
End With
Application.ScreenUpdating = True
End If
End Sub
Это вторая версия - добавил коллекцию для случая если несколько товаров пятого уровня (почему этого нет в примере?).
Приношу прощения, что не все нюансы указал, уважаемый Hugo - то, что Вы сделали, действительно волшебство, очень благодарен Вам, это действительно круто!
Со вчерашнего дня зачитываюсь литературой и смотрю видео по VBA, хоть мутно, но немножко начал понимать Ваш код - чтобы весь расщелкать, потребуется недели две, наверное)
А можете подсказать, дополнительно в код что добавить, чтобы учитывались до 10 уровней с разным количеством строк, а также данные в последующих столбцах?
Askabara написал: чтобы учитывались до 10 уровней с разным количеством строк
Ну если до 10 уровней это понятно при этом лучше сразу рассчитывать на любую вложенность, хотя может быть существенным разное количество уровней иерархии в разных группах. что чуть усложняет определение искомой строки с данными. А что вы под разным количеством строк имели в виду?
Hugo, как немакрукшник макрушнику :-) , приходилось делать подобное и я тогда рекурсивно подходил с передачей родильских уровней и формированием запаздывания с выводом. То есть строка с данными - последний потомок, это тогда, когда номер уровня или равен или сменился на меньший и если был хоть один потомок, то это родитель и его пропускаем. Но у меня был подвох, могли быть "уровни" без дочерних элементов. приходилось еще и формат ячейки отслеживать.
Я как-то не особо долго думал - в начале планировал что-то на словарях в словарях (и с рекурсией/подпроцедурой), но плюнул ибо заумно, да и просто на одном словаре отработало. Потом добавил коллекцию, хотя пример её не требвал.
Не ради рекламы - делал в своей надстройке, там можно сколько угодно уровней сделать и вывести по разному: Подготовить таблицу - строки Названия заголовков спецом не выдумывал, но можно назначить любые. Надстройка платная, но 30 дней будет работать на полную без проблем. Для конкретно последнего примера настройки выглядят так(скрин во вложении)
Под несколькими строками я имел ввиду, что товаров может быть от двух до 100 в последней группе, либо подгруппа может содержать от 1 до 10 наименований, т.е. предыдущие группировки могут содержать несколько наименований, разветвлений, их может быть разное количество, например может быть просто обувь - адидас, либо обувь - мужская - спортивная - адидас к примеру. Также в некоторых группах может быть 6 разделов, в некоторых 7, соответственно при формировании линейной таблицы данные могут быть смещены относительно друг друга, и для такого случая возможно ли будет спрограммировать таким образом, чтобы данные с цифрами/числами, начинающиеся со второго столбца в начальной таблице, в линейной таблице подтягивались после крайнего столбца с данными, т.е., если будет 7 группировок, то цифровые данные в том же порядке начинались с 8-го столбца, к примеру...
Если потребуется примерная структура с возможными сценариями, я могу вручную сформировать и разместить
Да, для такого зоопарка мой код не рассчитан... Там есть варианты вообще на 2 уровня, т.е. зоопарк от 2-х до 6-ти уровней. P.S. Хотя вот вроде удалось скорректировать малой кровью на до 6-ти уровней:
Скрытый текст
Код
Option Explicit
Sub tt()
Dim c As Range
Dim t0$, t1$, t2$, t3$, t4$, t5$, t$
Dim d As Object, k, el, i&
Set d = CreateObject("Scripting.Dictionary"): d.comparemode = 1
For Each c In [b10].CurrentRegion.Columns(1).Cells
If c.Font.Bold = False Then
t = t0 & "|" & t1 & "|" & t2 & "|" & t3 & "|" & t4 & "|" & t5
If Not d.exists(t) Then d.Add t, New Collection
'd.Item(t).Add c.Value
d.Item(t).Add c.Resize(, 9).Value
Else
Select Case c.IndentLevel
Case 0
t0 = c.Value: t1 = Empty: t2 = Empty: t3 = Empty: t4 = Empty: t5 = Empty: t = Empty
Case 1: t1 = c.Value
Case 2: t2 = c.Value
Case 3: t3 = c.Value
Case 4: t4 = c.Value
Case 5: t5 = c.Value
End Select
End If
Next
If d.Count Then
Application.ScreenUpdating = False
With Workbooks.Add(1).Sheets(1)
For Each k In d.keys
For Each el In d.Item(k)
i = i + 1
.Cells(i, 1).Resize(, 5) = Split(k, "|")
'.Cells(i, 6) = el
.Cells(i, 6).Resize(, 9) = el
Next
Next
.Columns.AutoFit
End With
Application.ScreenUpdating = True
End If
End Sub