Страницы: Пред. 1 2
RSS
Power query сделать непересекаемые периоды дат
 
вариант c комментами
Код
let
    dateList = Excel.CurrentWorkbook(){[Name="Таблица1"]}[Content],
    typed = Table.TransformColumnTypes(dateList,{{"Дата С", type date}, {"Дата ПО", type date}}),
    sorted = Table.Sort(typed, {"Код", {"Дата С", Order.Descending} }),    
    grouped=Table.Group(sorted,"Код", {"lastRenew", each  List.Max([Дата С])} ),
    joined=Table.NestedJoin(grouped,"Код", sorted,"Код",  "nest"),    
    indexed = Table.TransformColumns(joined, { {"nest", each Table.AddIndexColumn(_, "Index", 1, 1) } }),
//-UDF1
listrng = (this as table) => let  
    // те Статусы, которые выше   
    add= Table.AddColumn(this, "Initial", each Table.Range(this[[Статус],[Дата С],[Дата ПО]],0,[Index]-1)),    //CUMMULATED PREVIOUS    
    // развернули массивы Дат в колонку [dts] в prior_cummulated_subgroup of Initial:
    // -- UDF2
        listdts =  (this2 as table) => let  
            aa=  Table.AddColumn(this2, "dts", each List.Dates(_[Дата С],Duration.Days(_[Дата ПО] - _[Дата С]) + 1, #duration(1, 0, 0, 0)), type datetime )
        in aa,
    // -- implementation of UDF2
    trans= Table.TransformColumns(add, {"Initial", each listdts(_) } ),    
    // вывод в строки Initial - всех prior Дат 
    trans2= Table.TransformColumns(trans, {"Initial", each List.Sort(List.Distinct(List.Combine(_[dts])))}),     
    // исключение из каждого текущего prior Дат (т.е. тех, у которык уже более приоритетный Статус есть)
    current= Table.AddColumn(trans2, "curretdts", each List.Dates(_[Дата С],Duration.Days(_[Дата ПО] - _[Дата С]) + 1, #duration(1, 0, 0, 0)), type datetime ),
    crossremove= Table.AddColumn(current, "dts_In_Work", each  List.RemoveItems( _[curretdts], _[Initial]) )
in 
crossremove,    
    // - implementation of UDF1
    cumm = Table.TransformColumns(indexed, {"nest", each listrng(_)} ),                   
    #"Expanded nest" = Table.ExpandTableColumn(cumm, "nest", {"Статус", "dts_In_Work"}, {"Статус", "dts_In_Work"}),
    #"Expanded nest.dtsInWork" = Table.ExpandListColumn(#"Expanded nest", "dts_In_Work"),
    #"Changed Type" = Table.TransformColumnTypes(#"Expanded nest.dtsInWork",{{"dts_In_Work", type date}}),
    #"Removed Columns" = Table.RemoveColumns(#"Changed Type",{"lastRenew"})
in
    #"Removed Columns"
P.S.
MY REVIEW:
манипулировать подструктурами удобнее через UDF (с точки зрения синтаксиса)
ещё более глубокими подструктурами (иными по строению) - новыми (иными по обработке) UDF
и т.д. [особенно на первых порах]
Изменено: JeyCi - 30.10.2018 09:40:39
чтобы не гадать на кофейной гуще, кто вам отвечает и после этого не совершать кучу ошибок - обратитесь к собеседнику на ВЫ - ответ на ваш вопрос получите - а остальное вас не касается (п.п.п. на форумах)
 
Доброе время суток
Ещё один вариант
Код
let
    Source = Excel.CurrentWorkbook(){[Name="Таблица1"]}[Content],
    Typed = Table.TransformColumnTypes(Source,{{"Код", Int64.Type}, {"Статус", type text}, {"Дата С", type date}, {"Дата ПО", type date}}),
    Maker = Table.Group(Typed, {"Код"}, {"temp", (sub) =>
    let
        sortedByDateFrom = Table.Sort(sub, {{"Дата С", Order.Ascending}}),
        addStatusWeight = Table.AddIndexColumn(sortedByDateFrom, "weight"),
        addThroughDate = Table.AddColumn(addStatusWeight, "Дата", each List.Dates([Дата С], Duration.TotalDays([Дата ПО] - [Дата С]) + 1, #duration(1, 0, 0, 0))),
        expandThroughDate = Table.ExpandListColumn(addThroughDate[[Статус], [Дата], [weight]], "Дата"),
        DefineMaxStatusWeightOfThroughDate = Table.Group(expandThroughDate, {"Дата"}, {"temp", each Table.Max(_, "weight")}),
        result = Table.ExpandRecordColumn(DefineMaxStatusWeightOfThroughDate[[temp]], "temp", {"Статус", "Дата"})
    in
        result
    }),
    #"Expanded {0}" = Table.ExpandTableColumn(Maker, "temp", {"Статус", "Дата"}, {"Статус", "Дата"}),
    #"Sorted Rows" = Table.Sort(#"Expanded {0}",{{"Код", Order.Ascending}, {"Дата", Order.Ascending}}),
    #"Changed Type" = Table.TransformColumnTypes(#"Sorted Rows",{{"Статус", type text}, {"Дата", type date}})
in
    #"Changed Type"
Кончено компактнее по памяти было бы делать через List.Generate с определением границ интервалов дат по весу статуса, а уже потом создавать по этим интервалам список дат статусов, но возиться с организацией стека не очень хочется.
 
Цитата
Андрей VG написал:
Ещё один вариант
Цитата
JeyCi написал:
вариант c комментами
Супер, что уж тут говорить. Вникаю
 
а вообще, Андрей VG, конечно, прав - Table.Group - это сила (при работе со структурой, как с целым) !..
Алгоритм, минимизирующий память и максимизирующий скорость, - это тоже сила !..
p.s.
ваш List.Accumulate, который вы хотели, как раз имеет недостатки для вашей задачи: у вас state должен быть по сходствам, но в current вы хотите выводить различия... поэтому уже новый state (отражая различия) ну никак уже не будет показывать, что у вас уже было в более приоритетных статусах по сходству... имхо
p.p.s
List.Generate же, насколько понимаю, не обязан выводить ничего (только то, что вы его попросите), но выполняет инструкции, указанные вами по превращению переменных (и кстати помнит эти переменные в памяти, не в строках state or current)... имхо... вам как бы и надо вести 2 линии: что было - чтобы сравнивать потом на сходства, и чего не было - чтобы выводить отличия от прежнего (и добавлять в линию для поиска сходства далее, дабы потом снова выбросить новые все сходства), и вывести лишь отличия)... думаю так... (или, как написал  Андрей VG, - забрасывать пройденное в стек)... надо думать
чтобы не гадать на кофейной гуще, кто вам отвечает и после этого не совершать кучу ошибок - обратитесь к собеседнику на ВЫ - ответ на ваш вопрос получите - а остальное вас не касается (п.п.п. на форумах)
 

List.Generate
адаптация примера Андрей VG с линка #25 пост #9 на вашу задачу - можно так:

Код
let
    Source = Excel.CurrentWorkbook(){[Name="Таблица1"]}[Content],
    Typed = Table.TransformColumnTypes(Source,{{"Код", Int64.Type}, {"Статус", type text}, {"Дата С", type date}, {"Дата ПО", type date}}),
    Maker = Table.Group(Typed, {"Код"}, {"temp", (sub) =>
        let
            setRunningOrder = Table.Sort(sub, {{"Дата С", Order.Descending}}),        // Desc - acc. priority
            Count = Table.RowCount(sub),
            dts = Table.Buffer(setRunningOrder[[Статус],[Дата С],[Дата ПО]]),
            DateLists = Table.AddColumn(dts, "Дата", each List.Dates(_[Дата С], Duration.TotalDays(_[Дата ПО] - _[Дата С]) + 1, #duration(1, 0, 0, 0))),
 
            calcRunningTotal = List.Generate(
                //до id=0
                () => [id = 0 , runningDatesNEW = DateLists[Дата]{id}, runningDatesEXIST = DateLists[Дата]{id}], //N.B. если все running выставить в {} - {} record тоже задаётся! в output => нач. count с -1 -- ! потом убрать join'ом далее... ИЛИ БРАТЬ 1-ЫЙ !!! (как здесь)
                // от хвоста  
                each [id] < Count,       
                // ==> Инструкции… (List.Difference ИЛИ Table.Join (AntiJoun) --- N.B. List OR Table do you have)
                each [id = [id] + 1,  runningDatesNEW = List.Difference( DateLists[Дата]{id},[runningDatesEXIST]), runningDatesEXIST = List.Combine({[runningDatesEXIST], DateLists[Дата]{id}})], 
                each {[id], [runningDatesNEW],  [runningDatesEXIST]}
            ),
            // потом Join по Id
            makeRunningTable = Table.FromRows(calcRunningTotal, {"id", "runningDatesNEW", "runningDatesEXIST"}),
            addIdxForRunningJoin = Table.AddIndexColumn(setRunningOrder, "id"),            // от 0
            result = Table.Join(addIdxForRunningJoin, {"id"}, makeRunningTable, {"id"})    //здесь убирается запись с id=-1 (если надо) 
        in
        result
    }),    
    exp1 = Table.ExpandListColumn(Maker, "temp"),
    exp2 = Table.ExpandRecordColumn(exp1, "temp", { "Статус", "runningDatesNEW"}, { "Статус", "runningDatesNEW"}),
    exp_generated = Table.ExpandListColumn(exp2, "runningDatesNEW"),
    #"Changed Type" = Table.TransformColumnTypes(exp_generated, {{"runningDatesNEW", type date}})
in
#"Changed Type"

p.s.
файл прилагается (со всеми вариантами, прозвучавшими на ветке)...
p.p.s
обратить внимание, что при задании входных переменных - они тоже будут фигурировать в output (т.е. входные данные уже идут 1-й строкой в итоги) - или потом надо от начальной строки избавляться (если не подходит по общему смыслу итоговых сгенерированных строк - т.к. входящие данные служат только как входящие [но выводятся строки сгенерированные на их основе])...
Изменено: JeyCi - 02.11.2018 11:34:45
чтобы не гадать на кофейной гуще, кто вам отвечает и после этого не совершать кучу ошибок - обратитесь к собеседнику на ВЫ - ответ на ваш вопрос получите - а остальное вас не касается (п.п.п. на форумах)
 

Всем доброго дня.
Продолжаю ковыряться, но то ли четверг, то ли что-то со мной.
Подскажите где ошибка.
Мне нужно добавить столбец ДАТА ВЫХОДА со следующим рабочим днем от ДАТА ВХОДА.
Есть запрос, который выводит список выходных дней. Пытаюсь сделать так, но что-то не едут лыжи.

Код
#"Добавлен пользовательский объект" = Table.AddColumn(#"ClearTable", "Дата выхода", each List.Max(Table.FromRows(List.Generate(()=> [id=0, dExit=_[Дата входа]], List.Contains(#"Выходные дни",[dExit])=false, [id=[id]+1,dExit=Date.AddDays(_[Дата входа], [id])]), {"id", "dExit"})[dExit]))

Мне показалось, что в виде кода еще более неудобно.
А тема в продолжение изучения List.Generate, предложенного постами выше
Изменено: volfman - 08.11.2018 14:16:14
 
volfman, а какое отношение данный вопрос имеет к теме данного топика? И оформите код согласно правил форума - очень неудобночитаемо.
Вот горшок пустой, он предмет простой...
Страницы: Пред. 1 2
Наверх