1С.Разбираем многоуровневую шапку

#1C - шапка

Всем привет!

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

Зачастую пользователь начинает «руками» исправлять шапку таблицы, чтобы привести ее в удобную форму для дальнейшей работы.

Со своей стороны предложим несколько способов в помощь:

1. Для простой многоуровневой шапки таблицы, когда заполнены все заголовки полей (см. Пример1 в приложении) на просторах интернета можно увидеть такое:

  from=ИсточникДанных,

t=Table.Transpose(from),

mergecol = Table.CombineColumns(t,{"Column1", "Column2"},Combiner.CombineTextByDelimiter(".", QuoteStyle.None),"Headers"),

tr=Table.Transpose(mergecol),

to=Table.PromoteHeaders(tr)




Коротко про подход: Транспонируем таблицу, комбайним через разделитель , снова транспонируем и поднимаем заголовки. Далее таблицу можно свернуть для работы со сводной: Table.UnpivotOtherColumns ()



2. Для шапки, в которой заполнены не все поля (см. Пример 2) можно воспользоваться следующим кодом:

    from = ИсточникДанных,

lst=Table.ToColumns(Table.Range(from,0,2)),

newl=Table.ToList(Table.FillDown(Table.FromList(lst,(x)=>x),{"Column1"}),(x)=>x),

tr=List.Transform(newl,(x)=>Text.Combine(x,".")),

to=Table.RenameColumns(Table.Range(from,2),List.Zip({Table.ColumnNames(from),tr}))


Подход так же не сложный: «Откусили» шапку, преобразовали и приставили заново к телу таблицы.



Но что если уровней в таблице три и более или структура шапки похожа на таблицу в Примере 3 ?



3. На помощь может прийти решение, которое в большинстве случаев преобразует шапку таблицы в «плоский» формат:

fnParsHead=(table,num,optional delim,optional fill)=>

[ lst = List.Buffer(Table.ToColumns(Table.Range(table,0,num))),

delim = if delim=null then " " else delim,

f=(x,y)=>List.Accumulate( List.Zip({x,y}),

[i=false,j={}],

(s,c)=>[i=s[i]=true or c{0}<>null,j=if i then s[j]&{c{0}} else s[j]&{c{0}??c{1}}]

)[j],

g=(x)=>if fill=null then Text.Combine(x,delim) else Text.Combine(List.ReplaceValue(x,null,fill,Replacer.ReplaceValue),delim),

gen = List.Generate( ()=>[i=0,l=lst{i},o=l],

(x)=>x[i]<List.Count(lst),

(x)=>[i=x[i]+1,l=lst{i},o=f(l,x[o])],

(x)=>g(x[o])

),

out = Table.RenameColumns(Table.Range(table,num),List.Zip({Table.ColumnNames(table),gen}))][out],

from=ИсточникДанных,

to=fnParsHead(from,3,".")


Разберем данный код.

Эта функция анализирует первые несколько строк таблицы table, указанных в параметре num, далее по столбцам идёт объединение текста с использованием в качестве разделителя параметра delim. Опционально четвертый параметр fill позволяет задать строковое значение, которое будет использовано для заголовков нижних уровней в случае их отсутствия в данном столбце.

lst: Преобразуем в список строки таблицы с шапкой

delim: Опрашиваем входящий параметр-разделитель и при его отсутствии устанавливаем пробел

g: проверка параметра fill и если оно ненулевое, то добавляем к значению поля параметр, переданный в функцию fnParshead.

f:
на вход подаем два списка, связываем попарно и обрабатываем.

gen: Генератор, который собирает список для будущего заголовка таблицы в комплексе с функциями f и g.



Попробуйте на приложенных примерах разобрать каждый подход. И если что-то окажется полезным – значит все было не зря.



В большей степени пост предназначен для начинающих и продолжающих изучать функциональное программирование, хотя и профессионалы, надеюсь, смогут найти тут для себя что-то интересное.

Примеры, представленные выше показывают, как через редактор можно решить насущную задачу по разбору многоуровневой шапки. Так же предлагаю попробовать решить приложенные примеры, не прибегая к коду:

(мышкоклацем) – что получится?



С уважением к Вам. @CubRoot



PS^ Михаил, спасибо за помощь )