Страницы: 1 2 След.
RSS
Редизайнер. Power Query (PQ). Свернуть столбцы по группам
 
Доброго времени суток, Планетяне!

Туплю чёт, т.к. редко использую…
Подскажите, как в PQ корректно свернуть столбцы, чтобы преобразовать таблицу, как в примере?
В файле присутствует запрос и вывод его на лист.
Изменено: Jack Famous - 02.07.2019 12:17:36
Во всех делах очень полезно периодически ставить знак вопроса к тому, что вы с давних пор считали не требующим доказательств (Бертран Рассел) ►Благодарности сюда◄
 
Как-то так.
Код
let
    Source = Excel.CurrentWorkbook(){[Name="tbl"]}[Content],
    #"Unpivoted Other Columns" = Table.UnpivotOtherColumns(Source, {"Товар", "КОЛ-ВО"}, "Атрибут", "Значение"),
    #"Extracted Text Before Delimiter" = Table.TransformColumns(#"Unpivoted Other Columns", {{"Атрибут", each Text.BeforeDelimiter(_, " ", {0, RelativePosition.FromEnd}), type text}}),
    #"Trimmed Text" = Table.TransformColumns(#"Extracted Text Before Delimiter",{{"Атрибут", Text.Trim, type text}}),
    #"Added Index" = Table.AddIndexColumn(#"Trimmed Text", "Индекс", 0, 1),
    #"Integer-Divided Column" = Table.TransformColumns(#"Added Index", {{"Индекс", each Number.IntegerDivide(_, 3), Int64.Type}}),
    #"Pivoted Column" = Table.Pivot(#"Integer-Divided Column", List.Distinct(#"Integer-Divided Column"[Атрибут]), "Атрибут", "Значение"),
    #"Removed Columns" = Table.RemoveColumns(#"Pivoted Column",{"Индекс"})
in
    #"Removed Columns"

Вообще эту тему Максим 4 года назад уже разбирал в своем блоге. На заметку.  ;)
Вот горшок пустой, он предмет простой...
 
PooHkrd, благодарю за решение и ссылку, тёзка  ;)  думал, что попроще будет  :D
Во всех делах очень полезно периодически ставить знак вопроса к тому, что вы с давних пор считали не требующим доказательств (Бертран Рассел) ►Благодарности сюда◄
 
Да, там в комментариях Имке дала как раз похожий способ. Но! там теряется 4 товар, а он, я так понимаю, должен остаться.
Немного поигрался - последнее время люблю повозиться с такими преобразованиями:
Код
// tbl (3)
let
    Source = Excel.CurrentWorkbook(){[Name="tbl"]}[Content],
    Fixed = Table.SelectColumns(Source,{"Товар", "КОЛ-ВО"}),
    FixedColumns = Table.ToColumns(Fixed),
    Stack = Table.SelectColumns(Source,{"Покупатель 1", "Цена 1", "Стоимость 1", "Покупатель 2", "Цена 2", "Стоимость 2", "Покупатель 3", "Цена 3", "Стоимость 3"}),
    StackToColumns = Table.ToColumns(Stack),
    SplitStack = List.Split(StackToColumns,3),
    ToTables = List.Transform(SplitStack, each Table.FromColumns(FixedColumns & _)),
    GetOneTable = Table.Combine(ToTables),
    #"Renamed Columns" = Table.RenameColumns(GetOneTable,{{"Column3", "Покупатель"}, {"Column4", "Цена"}, {"Column5", "Стоимость"}, {"Column1", "Товар"}, {"Column2", "КОЛ-ВО"}}),
    FilteredNulls = Table.SelectRows(#"Renamed Columns", each [Покупатель] <> null or [Цена] <> null or [Стоимость] <> null),
    MergedToFixed = Table.NestedJoin(Fixed, {"Товар", "КОЛ-ВО"}, FilteredNulls, {"Товар", "КОЛ-ВО"}, "tab",JoinKind.LeftOuter),
    #"Expanded {0}" = Table.ExpandTableColumn(MergedToFixed, "tab", {"Покупатель", "Стоимость", "Цена"}, {"Покупатель", "Стоимость", "Цена"}),
    #"Changed Type" = Table.TransformColumnTypes(#"Expanded {0}",{{"Покупатель", type text}, {"Цена", type number}, {"Стоимость", type number}}),
    #"Sorted Rows" = Table.Sort(#"Changed Type",{{"Товар", Order.Ascending}})
in
    #"Sorted Rows"

Можно поиграться с универсальностью и забацать функцию, но лениво немного
F1 творит чудеса
 
Максим Зеленский, спасибо за вариант! Функция лишней точно не будет, а пока я всё-таки решил написать макрос на массивах, т.к. в PQ всё-таки пока что слабоват и чувствую себя неуверенно. Работает очень шустро))
Во всех делах очень полезно периодически ставить знак вопроса к тому, что вы с давних пор считали не требующим доказательств (Бертран Рассел) ►Благодарности сюда◄
 
до кучи, упрощенный вариант
Код
let
    Source = Excel.CurrentWorkbook(){[Name="tbl"]}[Content],
    fn=(_)=>#table({"Покупатель","Цена","Стоимость"},List.RemoveMatchingItems(List.Split(List.Skip(Record.FieldValues(_),2),3),{{}})),
    #"Added Custom" = Table.AddColumn(Source, "tbl", each fn(_))[[Товар], [#"КОЛ-ВО"],[tbl]],
    #"Expanded {0}" = Table.ExpandTableColumn(#"Added Custom", "tbl", {"Покупатель", "Цена", "Стоимость"})
in
    #"Expanded {0}"
 
Андрей Лящук, отлично.
PS
Только как теперь оставить строку с пустым 4 товаром и убрать остальные пустые?
Изменено: Максим Зеленский - 04.07.2019 15:46:34
F1 творит чудеса
 
Цитата
Максим Зеленский написал:
Но! там теряется 4 товар, а он, я так понимаю, должен остаться.
Ага, не заметил. Но это не сложно совсем переделать:
Код
let
    Source = Excel.CurrentWorkbook(){[Name="tbl"]}[Content],
    #"Grouped Rows" = Table.Group(Source, {"Товар", "КОЛ-ВО"}, {{"Таб", each 
    let 
        #"Unpivoted Other Columns" = Table.UnpivotOtherColumns(_, {"Товар", "КОЛ-ВО"}, "Атрибут", "Значение"),
        #"Extracted Text Before Delimiter" = Table.TransformColumns(#"Unpivoted Other Columns", {{"Атрибут", each Text.BeforeDelimiter(_, " ", {0, RelativePosition.FromEnd}), type text}}),
        #"Trimmed Text" = Table.TransformColumns(#"Extracted Text Before Delimiter",{{"Атрибут", Text.Trim, type text}}),
        #"Added Index" = Table.AddIndexColumn(#"Trimmed Text", "Индекс", 0, 1),
        #"Integer-Divided Column" = Table.TransformColumns(#"Added Index", {{"Индекс", each Number.IntegerDivide(_, 3), Int64.Type}}),
        #"Pivoted Column" = Table.Pivot(#"Integer-Divided Column", List.Distinct(#"Integer-Divided Column"[Атрибут]), "Атрибут", "Значение"),
        #"Removed Columns" = Table.RemoveColumns(#"Pivoted Column",{"Индекс"})
    in
        #"Removed Columns"
    , type table}}),
    #"Expanded {0}" = Table.ExpandTableColumn(#"Grouped Rows", "Таб", {"Покупатель", "Цена", "Стоимость"}, {"Покупатель", "Цена", "Стоимость"})
in
    #"Expanded {0}"
Вот горшок пустой, он предмет простой...
 
Добрый день, коллеги.
Решил потестировать. Код, генерирующий тестовый пример (шапка и имя таблицы из файла Алексея Jack Famous). Финальный вывод почти 600 тысяч строк.
Скрытый текст

Тёзка - 22 секунда. Код модифицировал под пожелания Максима.
Скрытый текст

Вариант Максима - 51 секунда.
Последний вариант Алексея - не дождался, вывод идёт приблизительно около 2000 строк в секунду.
Мой вариант - 17 секунд.
Скрытый текст
 
а у меня так получилось
Код
let
    Source = Excel.CurrentWorkbook(){[Name="tbl"]}[Content],
    fn=(_,a,b)=>#table({"Покупатель","Цена","Стоимость"},List.RemoveMatchingItems(List.Split(List.Skip(Record.FieldValues(_),a),b),{{},List.Repeat({null},b)})),
    #"Added Custom" = Table.AddColumn(Source, "tbl", each fn(_,2,3))[[Товар], [#"КОЛ-ВО"],[tbl]],
    #"Expanded {0}" = Table.ExpandTableColumn(#"Added Custom", "tbl", {"Покупатель", "Цена", "Стоимость"})
in
    #"Expanded {0}"
 
Цитата
Андрей Лящук написал:
а у меня так получилось
Здорово, спасибо! Отработало за 10 секунд.
 
как вы эти пользовательские функции делаете!!!
еще бы не готовый запрос выдавали, а видео, на котором было бы видно как вы поэтапно(пошагово) этот запрос делали)
глядишь и я бы смог такие функции сделать  
 
Если считать, что таблица состоит из "левой статичной" части (в примере 2 столбца: "товар" и "КОЛ-ВО") и "правой размножаемой" (в примере "покупатель 1" - "стоимость 3"), то мой макрос на массивах обрабатывает рабочий файл, в котором левая часть состоит из 18 столбцов, а правая из 40 столбцов (10 групп по 4 столбца), а строк 4 080 — за 0,1-0,2 сек на обычном ноутбучном железе (1-3 секунды, со всеми проверками + 2 раза пересчитать — перед и после запуска). Вот поэтому я и стараюсь пока что всё делать на макросах — они шустрые  :)

Все варианты на PQ замечательны и большое вам за них спасибо!
С удовольствием посмотрю за "соревнованиями" на скорость/оптимизацию))
Мой макрос без изменений
Пояснения:
1. "_allLeft" и "_allRight" — соответственно, "левая" и "правая" части исходной таблицы
2. "shChange" — системное имя листа-назначения для обращения напрямую из кода
3. "_changeFill" — область в таблице-назначения. По сути тут нужна только для того, чтобы удалить содержимое перед вставкой
4. "FFF_timer!" — публичная переменная из отдельного модуля. Отсутствует отсечка (FFF_timer=Timer) в коде, т.к. отсекается по событию листа, из которого потом и запускается этот основной код.
Изменено: Jack Famous - 05.07.2019 12:55:43
Во всех делах очень полезно периодически ставить знак вопроса к тому, что вы с давних пор считали не требующим доказательств (Бертран Рассел) ►Благодарности сюда◄
 
Jack Famous, ненавижу практику писать код через ":"  :D
читабельность кода страдает капитально, удобства редактирования тоже никакого. Разве что простыня короче, но это и всё.
F1 творит чудеса
 
Максим Зеленский, стараюсь сохранять логику при таком использовании)) или перечисление некоторых коротких и однотипных команд)

UPD: поправил основной код под спойлером  :D
Изменено: Jack Famous - 05.07.2019 12:54:08
Во всех делах очень полезно периодически ставить знак вопроса к тому, что вы с давних пор считали не требующим доказательств (Бертран Рассел) ►Благодарности сюда◄
 
artyrH, тут вопрос не в том, "как делать", а в "что делать".
На примере отличного кода Андрей Лящук, идея заключается в создании для каждой строки исходной таблицы доп.столбца, содержащего таблицу из N столбцов, где N - число столбцов в группах, которые надо переставить. В примере их три. Каждая строка такой таблицы - значения трех столбцов отдельной группы.

Андрей создает функцию, которая будет разбирать исходную строку. Специально создал комментарии инлайн, вдруг кому-то будет интересно:
Код
    fn=(_,a,b)=>
    /*
        _ - текущая строка
        a - сколько столбцов слева оставить
        b - размер одной группы (число столбцов в группе)
    */   

// определям таблицу:
        #table(
// с указанными названиями столбцов:
            {"Покупатель","Цена","Стоимость"},

/* 
далее определяем содержимое столбцов, пронумеровал порядок действий:
1. Получаем список из значений текущей строки
2. Убираем из них значения столбцов слева
3. разбиваем список из п.2 на список списков по 'b' элементов в каждом, т.е. получаем список из отдельных групп, каждая из которых тоже в виде списка
4. Убираем пустые группы
*/

            List.RemoveMatchingItems(           // 4. Убираем пустые группы
                List.Split(                                 // 3. разбиваем список из п.2 на список списков по 'b' элементов в каждом, т.е. получаем список из отдельных групп, каждая из которых тоже в виде списка
                    List.Skip(                             // 2. Убираем из них значения столбцов слева (две строки ниже - аргумент 'a')
                        Record.FieldValues(_),      // 1. Получаем список из значений текущей строки
                        a),                                  // 2. это сколько убрать начальных столбцов
                    b),                                      // 3. это размер группы
                {{},List.Repeat({null},b)}        // 4. здесь определяем, что будет считаться пустой группой: пустой список, или список из b элементов, содержащий только nulls
                )
            ),

// ниже вызываем функцию для создания нового столбца, после его добавления оставляем только начальные столбцы и столбец с табличками:
    #"Added Custom" = Table.AddColumn(Source, "tbl", each fn(_,2,3))[[Товар], [#"КОЛ-ВО"],[tbl]]

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

Пример, испольования
Код
// Query1
let
    Source = Excel.CurrentWorkbook(){[Name="tbl"]}[Content],
    test = UnpivotRepeatedColumns(Source, 2, 3, {"Покупатель", "Цена", "Стоимость"})
in
    test
 
Андрей VG, спасибо за универсальную функцию!  :idea:
Во всех делах очень полезно периодически ставить знак вопроса к тому, что вы с давних пор считали не требующим доказательств (Бертран Рассел) ►Благодарности сюда◄
 
Андрей VG,
мне кажется, логичнее вместо создания defaultRepeatNames с таймстемпом брать названия первой группы:
Код
defaultRepeatNames=List.Range(Table.ColumnNames(sourceTable), startFixColumnCount, repeatColumnCount)

Еще предложил бы не забивать временное имя константой (ну мало ли.... ну вдруг шальным образом именно так называется столбец), а вот так:
Код
tempNestedName = Text.NewGuid()

В конце тоже вот так можно :) :
Код
in
    Table.ExpandTableColumn(neededColumns, tempNestedName, defaultRepeatNames, if repeatColumnNames = null then defaultRepeatNames else repeatColumnNames)

В общем, подсократил на свой вкус:
Изменено: Максим Зеленский - 05.07.2019 17:05:37
F1 творит чудеса
 
Максим, спасибо за доработки. Года два выделенные функции не писал - смотрю подправили разработчики ситуацию, когда тело функции среда принудительно оборачивала в let/in.
 
Подскажите, пожалуйста, что я делаю не так - выдает ошибку: файл взяла тот, что приложил Jack, вставила функцию, что прописал Максим.
Изменено: turbidgirl - 06.07.2019 08:45:48
 
Цитата
turbidgirl написал:
что я делаю не так
Не обновляете Excel или надстройку Power Query (по картинке не видно до 2016 Excel или нет).
 
Была у меня, Андрей, такая мысль. Спасибо. Надо на рабочем компьютере попробовать будет, где версия Excel нормальная.
 
Чего-то вдруг меня нахлобучило, и решил еще вот такой вариант заделать:
Код
let
    fnUnpivotRepeatedColumns = (tab as table, countStay as number, countUnpivot as number) => 
        Table.CombineColumns( 
            tab, 
            List.Skip( Table.ColumnNames( tab ), countStay ), 
            (x) => Table.FromRows( List.RemoveMatchingItems( List.Split( x, countUnpivot ), {List.Repeat( {null}, countUnpivot )} ) ),
            "Сведено"),

    Источник = Excel.CurrentWorkbook(){[Name="tbl"]}[Content],
    Expanded = Table.ExpandTableColumn( fnUnpivotRepeatedColumns( Источник, 2, 3 ), "Сведено", {"Column1", "Column2", "Column3"}, {"Покупатель", "Цена", "Стоимость"})
in
    Expanded


Скрытый текст

Давненько хотел чего-нибудь этакое сотворить с Table.CombineColumns и вот.
Думаю для начинающих такое будет разобрать попроще чем универсальную функцию Андрея.
Изменено: PooHkrd - 27.12.2019 17:51:14
Вот горшок пустой, он предмет простой...
 
PooHkrd, спасибо всем откликнувшимся!  :)
Во всех делах очень полезно периодически ставить знак вопроса к тому, что вы с давних пор считали не требующим доказательств (Бертран Рассел) ►Благодарности сюда◄
 
Приветствую!
Подниму тему новой вариацией старой задачи
Как свернуть столбцы, как на скрине №1? Смог только дойти до этапа, как на скрине №2
Изменено: Jack Famous - 22.04.2021 16:20:00
Во всех делах очень полезно периодически ставить знак вопроса к тому, что вы с давних пор считали не требующим доказательств (Бертран Рассел) ►Благодарности сюда◄
 
Можно так:
Код
let
    Источник = Excel.CurrentWorkbook(){[Name="tbl"]}[Content],
    #"Другие столбцы с отмененным свертыванием" = Table.UnpivotOtherColumns(Источник, {"ЕСТЬ:"}, "Атрибут", "Значение"),
    #"Split Column by Position" = Table.SplitColumn(#"Другие столбцы с отмененным свертыванием", "Атрибут", Splitter.SplitTextByPositions({0, 2}, false), {"Атрибут.1", "Атрибут.2"}),
    #"Pivoted Column" = Table.Pivot(#"Split Column by Position", List.Distinct(#"Split Column by Position"[Атрибут.1]), "Атрибут.1", "Значение"),
    #"Removed Columns" = Table.RemoveColumns(#"Pivoted Column",{"Атрибут.2"})
in
    #"Removed Columns"

Тут главное определиться как правильно универсально разделить столбец, если в реальных данных не "Ед" и не "Зн"
Изменено: PooHkrd - 22.04.2021 17:00:06
Вот горшок пустой, он предмет простой...
 
PooHkrd, приветствую, тёзка и спасибо!  ;)
Во всех делах очень полезно периодически ставить знак вопроса к тому, что вы с давних пор считали не требующим доказательств (Бертран Рассел) ►Благодарности сюда◄
 
Цитата
PooHkrd написал:
если в реальных данных не "Ед" и не "Зн"
Привет, Алексеям.
Ну, можно же и так, без привязки
Код
let
    Source = Excel.CurrentWorkbook(){[Name="tbl"]}[Content],
    addUnpivot = Table.AddColumn(Source, "temp", (rec) =>
    let
        items = List.Range(Record.FieldValues(rec), 1),
        pairs = List.Split(items, List.Count(items) / 2)
    in
        Table.FromColumns(pairs)
    ),
    needed = Table.SelectColumns(addUnpivot, {"ЕСТЬ:", "temp"}),
    #"Expanded {0}" = Table.ExpandTableColumn(needed, "temp", {"Column1", "Column2"}),
    #"Filtered Rows" = Table.SelectRows(#"Expanded {0}", each ([Column2] <> null))
in
    #"Filtered Rows"
 
Андрей VG, привет ещё раз)
Кажется, я устарел
Во всех делах очень полезно периодически ставить знак вопроса к тому, что вы с давних пор считали не требующим доказательств (Бертран Рассел) ►Благодарности сюда◄
Страницы: 1 2 След.
Наверх