Поиск  Пользователи  Правила 
Закрыть
Логин:
Пароль:
Забыли свой пароль?
Регистрация
Войти
 
Страницы: 1
RSS
Преобразовать текстовый диапазон "с.. по.." в список значений Power Query
 
Здравствуйте! Помогите поизящнее решить несложную задачку.
Нужно в Power Query преобразовать текстовый диапазон вида: 1-6, 8, 20 в список значений: 1, 2, 3, 4, 5, 6, 8, 20.

Я сделал это в файле примера, но как-то неказисто получилось. Может есть более простое и короткое решение? Спасибо!
Изменено: simon100500 - 13 Июн 2018 21:47:35
 
UDF
Код
Function Diapazon(s)
    Dim ar, r, i!, u, ss
    ar = Split(Replace(s, " ", ""), ",")
    For r = 0 To UBound(ar)
        If InStr(1, ar(r), "-") > 0 Then
            u = Split(ar(r), "-")
            For i = u(0) To u(UBound(u))
                ss = IIf(Len(ss) = 0, i, ss & ", " & i)
            Next i
        Else
            ss = IIf(Len(ss) = 0, ar(r), ss & ", " & ar(r))
        End If
    Next r
     Diapazon = ss
End Function
 
Доброе время суток.
Вариант.
Код
let
    Source = Excel.CurrentWorkbook(){[Name="Таблица1"]}[Content],
    toList = Table.TransformColumns(Source, {"Диапазоны", (item) =>
    let
        toList = Text.Split(item, ","),
        preEval = List.Transform(toList, each "{" & Text.Replace(_, "-", "..") & "}"),
        toItems = List.Transform(preEval, each Expression.Evaluate(_))
    in
        List.Combine(toItems)
    }),
    expList = Table.ExpandListColumn(toList, "Диапазоны")
in
    expList
 
Код
Function DgtList(s$)
  Dim c, ar, i&
  ar = Split(s, ", "): s = ""
  For i = 0 To UBound(ar): If InStr(ar(i), "-") > 0 Then ar(i) = Replace(ar(i), "-", ":") Else ar(i) = ar(i) & ":" & ar(i)
  Next
  For Each c In Intersect(Columns(1), Range(Join(ar, ","))): s = s & c.Row & ",": Next
  DgtList = Left(s, Len(s) - 1)
End Function
Программисты - это люди, решающие проблемы, о существовании которых Вы не подозревали, методами, которых Вы не понимаете!
 
Андрей VG, а так?
Код
let
    Source = Excel.CurrentWorkbook(){[Name="Таблица1"]}[Content],
    toList = Table.TransformColumns(Source, {"Диапазоны", (item) =>
    let
        preEval ="{" & Text.Replace(item, "-", "..") & "}"
    in
        Expression.Evaluate(preEval)
    }),
    expList = Table.ExpandListColumn(toList, "Диапазоны")
in
    expList
F1 творит чудеса
 
Максим Зеленский, Андрей VG, очень красиво, но зачем там функцию городить, если можно записать вообще так?
Код
let
    Source = Excel.CurrentWorkbook(){[Name="Таблица1"]}[Content],
    toList = Table.TransformColumns(Source, {"Диапазоны", each Expression.Evaluate( "{" & Text.Replace(_, "-", "..") & "}" ) }),
    expList = Table.ExpandListColumn(toList, "Диапазоны")
in
    expList

Для наглядности?
 
Цитата
PooHkrd написал:
но зачем там функцию городить
Если возьмётесь через полгода - год править - поймёте, чем лучше пошаговая раскладка ;)
Цитата
Максим Зеленский написал:
а так?
Так точно - лучше. Спасибо!
 
Андрей VG, спасибо, как разберусь с корректным использованием самописных функций, так сразу начну применять, а пока мне так понятнее - так и пишу. Из всего, что видел про Expression.Evaluate() - это на мой взгляд самый наглядный пример.
 
Цитата
PooHkrd написал:
как разберусь с корректным использованием самописных функций
Я, собственно, про стремление к стилю формулистов Excel (у них это, правда, вынужденное действие). Так же тоже работает, но зачем так писать?
Код
Table.ExpandListColumn(Table.TransformColumns(Excel.CurrentWorkbook(){[Name="Таблица1"]}[Content], {"Диапазоны", each Expression.Evaluate("{" & Text.Replace(_, "-", "..") & "}")}), "Диапазоны")
 
Андрей VG,  8-0 не-не-не, я так не пишу - все с отступами, комментами и прочей атрибутикой - чему в универе учили. Я исключительно про использование самописных функций. Это надо в голове сначала уложить - а то напортачишь еще.
 
Цитата
PooHkrd написал:
исключительно про использование самописных функций
так а чем вот это
Код
each Expression.Evaluate( "{" & Text.Replace(_, "-", "..") & "}" )
по степени самописности отличается от вот этого:
Код
(item) =>
    let
        preEval ="{" & Text.Replace(item, "-", "..") & "}"
    in
        Expression.Evaluate(preEval)

когда each встречается больше 1 раза, тут возникает вопрос: какой именно _ имеется ввиду?
Код
each function(_, each _+1)
F1 творит чудеса
 
Максим Зеленский, тем что как работает конструкция each _ вы мне еще полгода назад очень внятно объяснили, я её в разных вариантов испробовал и её использование переходит в разряд навыков. Так же более менее начал осознавать как сделать функцию в отдельном запросе и передавать в неё аргументы. А вот объявление функции по ходу дела и особенно с двумя-тремя аргументами мне почему-то взрывает мозг. Особенно когда читаю суперинтересные статьи типа этой, но код в первом же комменте Сергея Лосева поначалу вызвал у меня шевеление волос на голове и не только. Сейчас вот начинаю осознавать что к чему, но полное понимание складывается не сразу - староват уже, мозги на шаблонах пытаются больше выезжать. А вам всем спасибо за разминку.
 
Цитата
PooHkrd написал:
А вот объявление функции по ходу дела и особенно с двумя-тремя аргументами мне почему-то взрывает мозг.
Ничего, это пройдет. :)  "По ходу дела" функция обявляется обычно там, где она требуется как аргумент. Например, в List.Transform второй аргумент - функция, применяемая к элементу списка. Ей передается один аргумент, а вот как его назвать - _ или item или vasyadurak - дело пишущего :) Ну и each равнозначен (_)=>

Вот четыре идентичные, по сути, записи:

Код
List.Transfrom(strings, Text.Proper)
List.Transfrom(strings, each Text.Proper(_))
List.Transfrom(strings, (_)=>Text.Proper(_))
List.Transform(strings, (item)=>Text.Proper(item)) 
Понятно, что если функцию стоит записать в несколько строк, то как 2, так 3 или 4 вариант дают нам такую возможность. Но если возникает вложенность разных итераторов, то мне проще переписать их руками, например, строку на входе я обозначу как row, элемент списка - как el или item, далее это поможет вспомнить, что именно я тут мучаю. Ну и сослаться при необходимости на аргумент более верхнего уровня тоже можно, удобно.

Сергей написал отличный код, но там ничего такого супер-необычного с точки зрения синтаксиса не использует. Там просто List.Accumulate третьим аргументом требует функцию, принимающую два аргумента, первый из которых текущее состояние аккумулятора, а второй - текущий элемент перебираемого списка. Он их обозвал как (sum,x), хотя мог так, как в документации приведено: (state, current). Ну, ему так удобнее было. Я так ленивый и вообще пишу в этом случае (s, c), хотя для читабельности это хуже.
F1 творит чудеса
 
Большое всем спасибо: за скорый ответ и объяснения!
Я подозревал, что существует какая-нибудь функция, которая берёт выражение из текстовой строки и выдаёт его результат. Ей оказалась Expression.Evaluate!
Изменено: simon100500 - 13 Июн 2018 21:52:13
Страницы: 1
Читают тему (гостей: 1)