Как применить формулу массива к каждому значению, возвращаемому другой формулой массива?

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

Я использую Microsoft 365 и хочу найти способ в Excel последовательно применять формулы массива – одну на выходе другой – для получения 2D таблицы.

Конкретно, я хочу применить regex с группами захвата к предоставленному пользователем блоку текста. В идеале REGEXEXTRACT() должен возвращать 2D массив, где каждая строка соответствует совпадению, а каждый столбец соответствует группе захвата. Однако в настоящее время REGEXEXTRACT() возвращает (используя аргумент return_mode) либо 1D массив, содержащий группы захвата первого совпадения, либо 1D массив, содержащий каждое полное совпадение (не учитывая группы захвата).

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

К сожалению, хотя 1) первый REGEXEXTRACT() работает нормально, 2) второй REGEXEXTRACT() работает нормально, когда применяется вручную к каждой строке, выводимой из первого, я не смог найти способ успешно автоматически воспроизводить формулу для любой строки. Если я использую оператор разлива #, хотя формула затем распространяется вертикально, она не выводит ничего горизонтально, что значит, возвращается только первая группа захвата.

Вот упрощенный пример, показывающий работу двух формул REGEXEXTRACT() для первой строки:

  • B1: Regex (в данном случае возвращает две группы захвата числовых данных)
  • B2: строка для поиска
  • B5: =TRANSPOSE(REGEXEXTRACT(B2,B1,1,1))
  • C5: =REGEXEXTRACT(B5,$B$1,2,1)

Электронная таблица, показывающая последовательные формулы REGEXEXTRACT()

Вот пример, показывающий, что разлив не работает одновременно по горизонтали и вертикали:

  • B1, B2, B5: как выше
  • C5: =REGEXEXTRACT(B5#,$B$1,2,1)

Электронная таблица, показывающая, что разлив не работает одновременно по горизонтали и вертикали

Я уверен, что это можно сделать в VBA, но я предпочел бы не прибегать к этому. Я чувствую, что упускаю что-то простое – есть ли это?

Существует известное (и обоснованное) ограничение обработки массивов в Excel, часто описываемое как “ограничение массива массивов”.

Существует множество способов обойти это ограничение. Возможно, один из самых распространенных – так называемый паттерн reduce/vstack.

В общем смысле, мы используем REDUCE для итерации по входному массиву, и внутри его LAMBDA используем VSTACK для накопления результатов обработки каждой входной строки.

Предположим, у меня есть ваши данные и еще одна строка (чтобы продемонстрировать, что это работает для нескольких строк) в B3:B4, тогда эта формула вернет результат:

=DROP(
    REDUCE(
        0,
        B3:B4,
        LAMBDA(a, b,
            LET(
                ar, TEXTSPLIT(b, CHAR(10)),
                rg, DROP(
                    REDUCE(
                        0,
                        ar,
                        LAMBDA(a, b,
                            VSTACK(a, REGEXEXTRACT(b, "(\d+).(\d+)", 2, 1))
                        )
                    ),
                    1
                ),
                VSTACK(a, HSTACK(EXPAND(b, ROWS(rg), 1, b), rg))
            )
        )
    ),
    1
)

введите описание изображения

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

После импорта функций STACKER в Advanced Formula Environment в Excel Labs:

введите описание изображения

Вам нужно только определить функцию для решения одной строки вашего ввода:

введите описание изображения

// Определите функцию, которая обрабатывает одну строку
SPLITLINES = LAMBDA(row,
    LET(
        ts, TEXTSPLIT(row,CHAR(10)),
        HSTACK(EXPAND(row, COLUMNS(ts), 1, row), TOCOL(ts))
    )
);

// Определите функцию, которая обрабатывает одно измерение
SPLITDIMENSIONS = LAMBDA(row,
    HSTACK(row,REGEXEXTRACT(INDEX(row,1,2),"(\d+).(\d+)",2,1))
);

И затем формула для решения вашей проблемы становится проще:

введите описание изображения

=VSTACKER(SPLITDIMENSIONS)(VSTACKER(SPLITLINES)(B3:B4))

Если вы хотите узнать больше о STACKER, вы можете просмотреть это видео и это последующее видео.

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

РЕДАКТИРОВАНИЕ:

Для обработки одной строки вы можете использовать эту формулу:

=DROP(REDUCE(0,TEXTSPLIT(B3,,CHAR(10)),LAMBDA(a,b,VSTACK(a,REGEXEXTRACT(b,"(\d+).(\d+)",2,1)))),1)

РЕДАКТИРОВАНИЕ 2:

Я просто хочу отметить, что для этой конкретной задачи, когда нужно разделить только 1 ячейку, самый простой ответ – это TEXTSPLIT. Я разместил отдельный ответ для этого.

С Excel 365 вы также можете использовать функции Python.

В вашем случае это кажется гораздо более простым решением:

[cell.split("x") for cell in xl("B2").splitlines()]

введите описание изображения

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

=TEXTSPLIT(B3,"x",CHAR(10))

Где “x” – это разделитель столбцов, а CHAR(10), который представляет разрыв строки, – это разделитель строк.

.

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

Вопрос о том, как применить формулу массива к каждому значению, полученному от другой формулы массива в Excel на платформе Microsoft 365, требует детального подхода. Проблема заключается в попытке извлечь и обработать данные с использованием формулы REGEXEXTRACT(), чтобы получить 2D-таблицу, и в то же время преодолеть некоторые ограничения, связанные с обработкой массивов в Excel.

Проблема

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

Ваша начальная идея заключалась в использовании TRANSPOSE() для превращения результата первой REGEXEXTRACT() в вертикальный список, после чего использовать вторую REGEXEXTRACT() для обработки этих элементов и получения групп захвата в горизонтальном направлении. Однако использование оператора разлива # не позволяет вам получить желаемый результат в двух измерениях.

Решение

Существует подтвержденное ограничение в Excel, известное как "ограничение массива массивов". Один из распространенных подходов к его обходу — паттерн REDUCE/VSTACK. Вот как это можно реализовать в вашем случае:

  1. Использование функции REDUCE с LAMBDA:

    =DROP(
       REDUCE(
           0,
           B3:B4,
           LAMBDA(a, b,
               LET(
                   ar, TEXTSPLIT(b, CHAR(10)),
                   rg, DROP(
                       REDUCE(
                           0,
                           ar,
                           LAMBDA(a, b,
                               VSTACK(a, REGEXEXTRACT(b, "(\d+).(\d+)", 2, 1))
                           )
                       ),
                       1
                   ),
                   VSTACK(a, HSTACK(EXPAND(b, ROWS(rg), 1, b), rg))
               )
           )
       ),
       1
    )

    Данный код использует функцию REDUCE для итерации по входному массиву и VSTACK для накопления результатов обработки каждой строки.

  2. Использование функции TEXTSPLIT и REGEXEXTRACT:

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

    =TEXTSPLIT(B3,"x",CHAR(10))
  3. Преимущества LAMBDA-функций и STACKER:

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

    SPLITLINES = LAMBDA(row,
       LET(
           ts, TEXTSPLIT(row,CHAR(10)),
           HSTACK(EXPAND(row, COLUMNS(ts), 1, row), TOCOL(ts))
       )
    );
    
    SPLITDIMENSIONS = LAMBDA(row,
       HSTACK(row,REGEXEXTRACT(INDEX(row,1,2),"(\d+).(\d+)",2,1))
    );
    
    =VSTACKER(SPLITDIMENSIONS)(VSTACKER(SPLITLINES)(B3:B4))

Этот подход упрощает сложные операции с массивами и решает проблему применения одного массива к результатам другого.

Заключение

Решение вашего вопроса требует последовательного применения нескольких функций и паттернов, чтобы обойти ограничения обработки массивов в Excel. Использование LAMBDA-функций и паттерна REDUCE/VSTACK позволяет добиться желаемого поведения в Excel с минимальными усилиями и без необходимости использования VBA.

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

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