Биграмы строки в Power Query M

Вопрос или проблема

Я пытаюсь написать пользовательскую функцию Power Query, чтобы преобразовать данную строку в список ее биграмм.

Например, “Привет, мир” должен вывести

Список
1 Пр
2 ри
3 ив
4 ве
5 ет
6 ,
7 м
8 и
9 р

Я наткнулся на реализацию рекурсивной функции на M здесь, что привело меня к написанию этого:

( String1 as text ) =>
let
    S1 = Text.Remove(String1, " "),
    String1_Tokens = Text.ToList(S1),
    N = List.Count(String1_Tokens),
    func = (x as list, n as number, y as list) =>
        let 
            Calc = Text.Combine({x(n), x(n+1)}),
            Lister = List.Combine({y,{Calc}}),
            Check = if n = N-1 then Lister else @func(x, n+1, Lister)
        in Check,
    res = func(String1_Tokens, 1, {})
in res

Основная идея заключается в том, что строка очищается от пробелов и разбивается на список ее составных символов. Этот список затем передается в функцию, которая берет nй и n+1й символ в списке и объединяет их, затем добавляет к уже существующему списку биграмм. Это повторяется, пока список символов не исчерпан.

При попытке вызвать эту функцию с входной строкой я получаю следующую ошибку:

Произошла ошибка в запросе ‘ ‘. Expression.Error: Мы не можем преобразовать значение типа List в тип Function.
Детали:
Значение=[List]
Тип=[Type]

Что я упускаю? Я довольно нов в M, поэтому чувствую, что здесь мне явно не хватает чего-то основного.

Вы почти сделали это!

( String1 as text ) =>
let
    S1 = Text.Remove(String1, " "), // Удалить пробелы
    String1_Tokens = Text.ToList(S1), // Преобразовать строку в список символов
    N = List.Count(String1_Tokens), // Получить длину списка
    func = (x as list, n as number, y as list) =>
        let 
            // Объединить текущий и следующий символы
            Calc = Text.Combine({x{n}, x{n+1}}),
            // Добавить результат в список
            Lister = List.Combine({y, {Calc}}),
            // Проверить, если мы на предпоследнем элементе, остановить рекурсию, если это так
            Check = if n = N-2 then Lister else @func(x, n+1, Lister)
        in 
            Check,
    // Начать рекурсию с индекса 0
    res = func(String1_Tokens, 0, {})
in 
    res

Дополнительная заметка: я думаю, вы написали очень элегантную рекурсивную функцию, но если бы я делал это (не то чтобы я был экспертом, это просто то, что мне нравится делать), я бы избегал использования рекурсии (в основном потому, что я всегда теряюсь в ней):

( String1 as text ) =>
let
    S1 = Text.Remove(String1, " "),    // Удалить пробелы
    charList = Text.ToList(S1),        // Преобразовать строку в список символов
    N = List.Count(charList),          // Получить количество в списке
    positions = List.Numbers(0, N-1),  // Создать список позиций от 0 до N-1
    bigrams = List.Transform(positions, each if _ < N-1 then Text.Combine({charList{_}, charList{_+1}}) else null),
                                       // Удалить любые значения null (последний элемент может быть null из-за условия if)
    cleanedBigrams = List.RemoveNulls(bigrams)
in
    cleanedBigrams

Ответ или решение

Как получить биграмы строки в Power Query M

Вопрос, который вы подняли, касается извлечения биграмм из строки в Power Query M, и ваша реализация действительно близка к правильному решению. Ниже я предложу подробное объяснение задачи и исправления, которые помогут вам достичь желаемого результата.

Что такое биграммы?
Биграмма представляет собой последовательность из двух символов, которые идут один за другим. Например, в строке "Hi World" биграммы будут: "Hi", "iW", "Wo", "or", "rl" и "ld".

1. Анализ Вашего Кода

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

  • Ошибка, о которой вы сообщаете, возникает из-за неправильного обращения с индексами и, возможно, ошибочного понимания об использовании List.Combine.
  • Вместо использования n = N-1, вам следует проверять n = N-2, чтобы не выходить за пределы списка.

2. Исправленный Код

Вот исправленная версия вашей рекурсивной функции:

(String1 as text) =>
let
    S1 = Text.Remove(String1, " "), // Убираем пробелы
    String1_Tokens = Text.ToList(S1), // Преобразуем строку в список символов
    N = List.Count(String1_Tokens), // Получаем длину списка
    func = (x as list, n as number, y as list) =>
        let 
            // Объединяем текущий и следующий символы
            Calc = Text.Combine({x{n}, x{n+1}}),
            // Добавляем результат в список
            Lister = List.Combine({y, {Calc}}),
            // Проверяем, находимся ли мы на предпоследнем элементе
            Check = if n = N-2 then Lister else @func(x, n+1, Lister)
        in 
            Check,
    // Запускаем рекурсию с первого индекса
    res = func(String1_Tokens, 0, {})
in 
    res

3. Альтернативный Итеративный Метод

Если рекурсия кажется сложной, других разработчиков может привлечь итеративный подход. Вот пример того, как это можно реализовать без рекурсии:

(String1 as text) =>
let
    S1 = Text.Remove(String1, " "),    // Убираем пробелы
    charList = Text.ToList(S1),        // Преобразуем строку в список символов
    N = List.Count(charList),          // Получаем количество символов
    positions = List.Numbers(0, N-1),  // Создаем список индексов
    bigrams = List.Transform(positions, each if _ < N-1 then Text.Combine({charList{_}, charList{_+1}}) else null),
    cleanedBigrams = List.RemoveNulls(bigrams) // Убираем возможные null-значения
in
    cleanedBigrams

4. Заключение

Теперь у вас есть два подхода для извлечения биграмм из строки в Power Query M. Рекурсивный подход и итеративный метод оба являются действительными, и выбор между ними зависит от ваших предпочтений и требований производительности.

Эти методы обеспечивают корректный способ генерации биграмм, подходя к задаче с разных сторон. Не забудьте протестировать код с различными входными строками для проверки корректности работы.

Если у вас останутся дополнительные вопросы или возникнут трудности в процессе выполнения, не стесняйтесь обращаться за помощью!

Оцените материал
Добавить комментарий

Капча загружается...