Хитрости »
30 Ноябрь 2022 2818 просмотров
Иногда, при работе с «чужими» файлами(т.е. с теми, которые были созданы или отредактированы на другом ПК), в формулах можно встретить формулы, которые начинаются на =_xlfn.(нечто вроде: =_xlfn.MAXIFS, _xlfn.IFERROR и т.п.)
При первом открытии файла такие функции показывают последний успешно вычисленный результат и при вычислении не обновляются, а если попытаться их пересчитать вручную, то в результате можно получить ошибку #ИМЯ!(#NAME!).
Что это и откуда? Для начала попробуем разобраться откуда берется это загадочное _xlfn. и что оно означает. Таким префиксом обозначаются функции, которые были созданы в более новых версиях Excel(чем та, в которой на данный момент открыт файл) и в текущей версии отсутствуют. По сути они читаются как =_xlfn.ИМЯ_ФУНКЦИИ. Например, =_xlfn.MAXIFS – это функция МАКСЕСЛИ(MAXIFS), _xlfn.IFERROR – ЕСЛИОШИБКА(IFERROR), _xlfn.UNIQUE – УНИК(UNIQUE) и т.д. Т.е. после самого префикса _xlfn идет как раз имя недоступной функции на английском. Если Вы увидели такой префикс в своем Excel в какой-либо формуле на листе — значит ваш Excel не поддерживает ту функцию, которая указана после префикса _xlfn.
Ниже перечень некоторых функций с их переводом на русскую локализацию и версии, начиная с которых эти функции будут работать(соответственно для версий ниже функции недоступны):
Префикс | Функция и доступность |
---|---|
_xlfn.IFERROR | ЕСЛИОШИБКА (доступна, начиная с Excel 2007) |
_xlfn.AGGREGATE | АГРЕГАТ (доступна, начиная с Excel 2010) |
_xlfn.GAMMA | ГАММА (доступна, начиная с Excel 2013) |
_xlfn.MAXIFS | МАКСЕСЛИ (доступна, начиная с Excel 2019 и в Excel 365) |
_xlfn.MINIFS | МИНЕСЛИ (доступна, начиная с Excel 2019 и в Excel 365) |
_xlfn.CONCAT | СЦЕП (доступна, начиная с Excel 2019 и в Excel 365) |
_xlfn.SORTBY | СОРТПО (доступна, начиная с Excel 2019 и в Excel 365) |
_xlfn.XLOOKUP | ПРОСМОТРХ (доступна, начиная с Excel 2021 и в Excel 365) |
_xlfn.UNIQUE | УНИК (доступна, начиная с Excel 2021 и в Excel 365) |
_xlfn.LAMBDA | LAMBDA (доступна только в Excel 365) |
_xlfn.TOCOL | ПОСТОЛБЦ (доступна только в Excel 365) |
_xlfn.TOROW | ПОСТРОК (доступна только в Excel 365) |
Конечно, в этой таблице перечислены далеко не все функции и их может быть гораздо больше и список будет расти, т.к. Microsoft на данный момент постоянно пополняет коллекцию функций в новых версиях.
Как же появляется это самое _xlfn.ИМЯ_ФУНКЦИИ и откуда Excel вообще понимает, какой именно функции нет и что писать после _xlfn, если в самом текущем Excel такой функции нет? Здесь все достаточно просто — _xlfn.ИМЯ_ФУНКЦИИ создается в тот момент, когда на лист записывается функция, у которой могут быть проблемы с вычислением в более старых версиях. Т.е. создается это в самой исходной книге и еще в той версии Excel, которая эту функцию успешно может вычислить. А записывается в диспетчер имен, как новая именованная формула(вкладка Формулы(Formulas) —Диспетчер имен(Name Manager)). При этом имена эти создаются скрытыми – т.е. просто вызвав диспетчер имен мы эти все _xlfn не увидим. И удалить эти имена тоже нельзя, даже если до них добраться.
Так же можно встретить и чуть иной префикс: _xlfn._xlws.SORT и _xlfn._xlws.FILTER. Это как правило относится к формулам динамических массивов. SORT – СОРТ и FILTER – ФИЛЬТР. Эти функции записываются всегда только в одну ячейку, но результат возвращают сразу в несколько. При этом количество занимаемых ячеек в итоге динамически изменяется в зависимости от того, сколько строк и столбцов передано в качестве исходных данных и сколько после обработки было возвращено функцией.
А еще есть и такие имена: _xlfn.ANCHORARRAY и _xlfn.SINGLE. Они тоже относятся к динамическим массивам, но не являются напрямую именно функциями:
Можно ли исправить?
Как же быть, если одна из таких функций попалась в файле? Можно ли как-то её все же сделать вычисляемой?
Для того, чтобы ответить на эти вопросы разберемся
для чего это придумано
. Сделано такое именование(
_xlfn.ИМЯ_ФУНКЦИИ
) неподдерживаемых функций для того, чтобы можно было безошибочно определить, какая именно функция не доступна и при этом не сломать всю формулу, в которой такая функция используется. Но вычислить её, увы, не получится никак. Ведь раз появилось
_xlfn
— функции просто нет в текущей версии, а значит вычислить именно её невозможно. Но если определить имя функции(которое записано после префикса) — можно обратиться к справке Microsoft, найти эту функцию и попробовать заменить её доступной функцией(или связкой функций), которая будет выполнять ту же задачу. Да, далеко не всегда для этого может хватить знаний, а в некоторых случаях и вовсе придется использовать VBA для восполнения функционала, т.к. какие-то функции будет невозможно воспроизвести встроенными. Но других вариантов все равно нет: либо так, либо устанавливать ту версию Excel, в которой эти функции есть.
В данной статье я, к сожалению, тоже никаких однозначных рекомендаций по замене
_xlfn
не дам, т.к. все зависит от конкретной задачи, которая выполняется функцией. Могу лишь привести пару примеров простой замены. Например, возьмем классическую ситуацию — есть таблица отгрузок товара:
надо определить самую минимальную, но при этом не учитывать нулевые отгрузки, т.к. в выходные отгрузка не производится, но в отчете нулевые отгрузки все же есть. В Excel 2019 и новее можно применить одну функцию:
=МИНЕСЛИ(B2:B10;B2:B10;»>0″)
=MINIFS(B2:B10,B2:B10,»>0″)
в более старых версиях вместо неё появится =
_xlfn.MINIFS(B2:B10;B2:B10;»>0″)
и её придется заменить такой формулой массива:
=МИН(ЕСЛИ(B2:B10>0;B2:B10))
=MIN(IF(B2:B10>0,B2:B10))
Или другая задача, которая в Excel 2019 и новее легко решается функцией
МАКСЕСЛИ(MAXIFS)
. Из таблицы ниже необходимо определить максимальную сумму по операции «приход»:
=МАКСЕСЛИ(A2:A10;B2:B10;»приход»)
=MAXIFS(A2:A10,B2:B10,»приход»)
в более старых версиях придется опять же решать задачу при помощи нескольких функций формулой массива:
=МАКС(ЕСЛИ(B2:B10=»приход»;A2:A10))
=MAX(IF(B2:B10=»приход»,A2:A10))
А такие функции как
СОРТ(SORT)
и
ФИЛЬТР(FILTER)
так просто заменить не получится — там уже необходимо применять достаточно серьезные связки функций, да еще и заранее определять минимально необходимое количество ячеек для вывода результата и обрабатывать ошибки «лишних» строк.
Статья помогла? Поделись ссылкой с друзьями!
Видеоуроки
Поиск по меткам
Access
apple watch
Multex
Power Query и Power BI
VBA управление кодами
Бесплатные надстройки
Дата и время
Записки
ИП
Надстройки
Печать
Политика Конфиденциальности
Почта
Программы
Работа с приложениями
Разработка приложений
Росстат
Тренинги и вебинары
Финансовые
Форматирование
Функции Excel
акции MulTEx
ссылки
статистика
На чтение 2 мин Просмотров 921 Опубликовано 26.06.2021
Обновлено 14.02.2023
Икселефэн, прямо шершеляфам.
Когда я работал в файле по захвату мирового господства и формула в ячейке достигла небывалой толщины, успев понтонуться перед друзьями, какую я мегаформулу накалякал, а потом сохранил и снова открыл, я увидел болт. Самый настоящий черный болт из браззерс.
В этой формуле одна из функций была заменена на другую с префиксом _xlfn.
Давай разбираться, гуглить. Как ни странно, помог сам хелп майкрософта. Обычно официальные хелпы можно смело сливать в унитаз, и решение находишь от других пользователей, а тут прям удивительно.
Я понял, что я использовал функцию, которая якобы не поддерживается в моем офисе. Но как блеать? Если она у меня выпадала в списке, а после следующего раза она пропала?
Если конкретно, то я говорю про функцию СЦЕП. Сначала я пользовался ею, а при следующем запуске вместо нее появилось _xlfn.CONCAT.
Видя эту хуиту, я так понял, что префиксом _xlfn офис сказал, что функция не поддерживается и предложил альтернативу — конкатенацию (CONCAT). Я правда не вдуплил, почему ее, т.к. там есть ближайшая альтернатива — СЦЕПИТЬ.
Давай проверять наличие функции СЦЕП. И реально, теперь она пропала, вместо нее выводится СЦЕПИТЬ.
Короче, заменил СЦЕП на СЦЕПИТЬ (на более старую) и всё заработало.
П.С. я был готов даже купить лицензионный офис, но без ста грамм не разберешься, где и чего покупать. А где-то вообще говорится, что десктопная версия офис 2019 это вообще не то, что офис 365 по подписке. Короче мутная херня какая-то.
137541cookie-check_xlfn в microsoft office. Что это такое?
Excel для Microsoft 365 Excel для Microsoft 365 для Mac Excel для Интернета Excel 2021 Excel 2021 для Mac Excel 2019 Excel 2019 для Mac Excel 2016 Excel 2016 для Mac Excel 2013 Excel 2010 Excel 2007 Еще…Меньше
Проблема
Объект _xlfn. Префикс отображается перед функцией в формуле. Когда формула вычисляется, отображается #NAME? (значение ошибки).
Причина
Книга Excel содержит функцию, которая не поддерживается в версии Excel, которая выполняется в данный момент. Например, вы могли открыть книгу, содержащую функцию IFERROR, которая не поддерживается в версиях Excel более ранних версий, чем Excel 2007. Функции, которые не поддерживаются в версиях Excel, предшествующих Excel 2007, включают: AVERAGEIF, AVERAGEIFS, MAXIFS, MINIFS, IFS, CUBEKPIMEMBER, CUBEMEMBER, CUBEMEMBERPROPERTY, CUBERANKEDMEMBER, CUBESET, CUBESETCOUNT, CUBEVALUE, COUNTIFS, IFERROR и SUMIFS.
Решение
Удалите неподдерживаемые функции или, если возможно, замените неподдерживаемые функции поддерживаемыми функциями.
Дополнительные сведения
Вы всегда можете задать вопрос специалисту Excel Tech Community или попросить помощи в сообществе Answers community.
См. также
Функции Excel (по алфавиту)
Функции Excel (по категориям)
Нужна дополнительная помощь?
If you open up a spreadsheet that you did not create, you may run into the «__xlfn» prefix before certain functions. The generic meaning of xlfn is «unsupported function». Typically, it indicates that the worksheet was created in a newer version of Excel and uses functions not yet available the version currently running.
In the example shown, the UNIQUE function is used to extract unique values from a range of data. UNIQUE is only available in Excel 365, and was introduced in 2020. When the workbook is opened in an older version of Excel, the __xlfn prefix appears. Note that the original result is still displayed. However, the formula will not update to show a new result if data changes.
Solution or workaround
If you open the same workbook in a version of Excel that contains the missing function(s), the _xlfn prefix will be disappear and the function will calculate normally. If this is not possible, you might be able to use a another formula that does not not rely on the newer function.
Despite how amazing Excel is there are times when you’ll find yourself shaking with fear! For example, have you ever seen anything as scary as this =ISERROR(FIND(_xlfn.CONCAT($A2:$E2),_xlfn.CONCAT($I$2:$M$6))) What is xlfn ???
What’s The Story?
You open your friend’s Excel file and discover that some of the formulas aren’t working and include the letters XLFN ! You call your friend but he says that everything looks perfectly fine on his laptop. Did you get too much sun? Did you eat some bad fish? Did you smoke one of Oz du Soleil’s cigars?
What Is XLFN?
xlfn is a prefix added to functions that don’t exist in the version of Excel that you are using.
You have Excel 2013 and your friend has a newer version of Excel (Office 365 or Excel 2016). He uses a cool new function and sends the file to you. As you have Excel 2013 this cool new function doesn’t yet exist and you see xlfn in front of the function.
Recent XLFN Example
Last year I discovered David Hager’s Excel blog. He shares a lot of neat ideas. I recently saw this post: Conditional Format Rows in List 1 that are Not in List 2
When I opened the file I noticed that the solution wasn’t working for me. I went back to David’s post and looked at this pic:
I noticed that David used the CONCAT function. This must be a new Excel 2016 (or Office365?) function! There are a bunch of really interesting new functions but I’m still using Excel 2013.
What Does Microsoft Recommend?
“Remove the unsupported functions, or if possible, replace the unsupported functions with supported functions.” Also, read this.
OK. So, Is There A Workaround?
Although not as easy as David’s solution we can still produce the same end result.
Here are the steps to my workaround solution:
- Use a helper formula to concatenate all values in both tables: (i.e. =K2&L2&M2&N2&O2 )
- Adding this =ISNUMBER(MATCH(A2,$J$2:$J$6,0)) shows whether or not the row is found (Cell A2 is key in table 1. Column J is key in table 2)
- Add this formula inside your conditional formatting rule: =$B2=FALSE
Excel 2013 Workaround Solution
Here is David’s Excel file that includes my workaround solution for those that don’t have Excel 2016.
Learn From Excel MVP David Hager
You can find David at https://dhexcel1.wordpress.com/ and https://twitter.com/dhExcel
About Me
My name is Kevin Lehrbass. I live in Markham, Ontario, Canada. I’ve been studying, supporting, building, troubleshooting, teaching and dreaming in Excel since 2001. I’m a Data Analyst.
There are so many amazing things that you can do with Excel.
Check out my recommended Excel Training section.
Check out my videos and my blog posts.
Away from Excel I enjoy learning Spanish, playing Chess, hanging out with Cali and Fenton and reading Excel books 🙂
Если вы открываете электронную таблицу, которую не создавали, вы можете встретить префикс «__xlfn» перед некоторыми функциями. Общее значение xlfn — «неподдерживаемая функция». Как правило, это означает, что рабочий лист был создан в более новой версии Excel и использует функции, недоступные в текущей версии.
В показанном примере функция XLOOKUP используется для поиска. XLOOKUP доступен только в Excel 365 и был представлен в 2020 году. Когда книга открывается в более старой версии Excel, появляется префикс __xlfn. Обратите внимание, что исходный результат все еще отображается. Однако формула не будет обновляться, чтобы показать новый результат, если данные изменятся.
Решение или обходной путь
Если вы откроете ту же книгу в версии Excel, которая содержит недостающую функцию (-ы), префикс _xlfn исчезнет, и функция будет рассчитываться нормально. Если это невозможно, вы можете использовать другую формулу, которая не зависит от новой функции.
1 Answer
Sorted by:
Reset to default
2
Excel uses _xlfn.
for formulas and _xlpm.
for LET
& LAMBDA
arguments for backwards compatibility.
It informs previous versions of Excel that this is a valid formula in the future, and Excel shows the stored values instead of errors.
Improve this answer
edited Apr 21, 2022 at 9:55
answered Apr 21, 2022 at 9:50
FilcukFilcuk
15418 bronze badges
Add a comment
|
Your Answer
Sign up or log in
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Name
Required, but never shown
By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy
Not the answer you’re looking for? Browse other questions tagged
- excel
- excel-formula
or ask your own question.
Not the answer you’re looking for? Browse other questions tagged
- excel
- excel-formula
or ask your own question.
xlfn
A pseudo functional programming library for Excel VBA.
After working for some time in an limited Windows environment without Python or Haskell and making Excel VBA modules, wouldn’t it be nice to have a small piece of functional programming on VBA to ease the development pain? So with a little magic from Application.Run and inspiration from Python’s fn.py, here is a quasi functional programming library for and done purely in VBA.
To God I plant this seed, may it turn into a forest
Introduction
Since VBA doesn’t have lambdas or closure or the first class functions, you can’t declare function variables. A little cheap but the other workaround for this is that you can declare String variables that contain the function name you want to invoke, so this is the route this library takes. This is done by Application.Run which serious flaws. One serious weak point is that functions invoked by Application.Run cannot return value. So how do we go about the return mechanism? Cheap but it can be done by declaring a global variable as the return holder and returning this value after the function invokation which is defined here as Fn.Result.
So in short, we have to refit our functions so that they can be «invokable» by Application.Run. Take this simple sample addition function in the module MyModule.
Public Function Add(A As Long, B as Long) as Long Add = A + B End Function
The newly reflavored function with the above workaround
Public Sub Add_(A as Long, B as Long) Fn.Result = A + B End Sub
Not much of a difference except the return mechanism and the function header without the return type. Now to invoke this quasi function is done through Fn.Invoke seen here.
Debug.Print MyModule.Add(1, 2) Debug.Print Fn.Invoke("MyModule.Add_", Array(1, 2)) Debug.Print Fn.InvokeTwoArgs("MyModule.Add_", 1, 2)
Note the way functions are invoked using their full name([Module Name].[Method Name]) and how the arguments are wrapped in the Array() function, a little cumbersome but a necessary evil since you can’t call the functions straight. Now with this function mechanism, the core functional method Filter, Reduce and Map can be implemented nicely. A sample of FnArrayUtil.Filter is shown here.
' Lambda definition Public Sub IsOdd_(Val as Long) Fn.Result = ((Val Mod 2) = 1) End Sub ' Functional Programming Style Public Sub FilteringUsingFP() Dim MyVals as Variant, OddVals as Variant MyVals = Array(1, 2, 4, 5, 7, 8, 10) OddVals = FnArrayUtil.Filter("MyModule.IsOdd_", MyVals) ' Filter at work Debug.Print ArrayUtil.Print_(OddVals) ' Returns [1, 5, 7] End Sub ' Vanilla VBA with ArrayUtil Public Sub FilteringWithoutFP() Dim MyVals as Variant MyVals = Array(1, 2, 4, 5, 7, 8 , 10) ' Boilerplate code to filter an array Dim OddVals as Variant, ValIndex as Long, MyValIndex as Long, MyVal as Long OddVals = ArrayUtil.CloneSize(MyVals) ' Create an array with the same LBound and UBound as MyVals ValIndex = 0 ' Looping the array boilerplate For MyValIndex = 0 to UBound(MyVals) MyVal = MyVals(MyValIndex) If ((MyVal Mod 2 ) = 1) Then ' Filtering here OddVals(ValIndex) = MyVal ' Adding an array the hard way ValIndex = ValIndex + 1 End if Next ' Trimming the array size, can be put in a method as well but more efficient in this form If ValIndex = 0 Then OddVals = Array() Else ReDim Preserve OddVals(0 to ValIndex - 1) End if Debug.Print ArrayUtil.Print_(OddVals) ' Same as above End Sub
Compare the code, without using FP there would be some boilerplate just to filter a simple array although it can be still shortened. The mechanism of lambdas here are somewhat cumbersome but with the ability of Map, Filter and Reduce at the ready, it’s a small price to pay for these three functional functions. There are others such as ZipWith, Sort, and so on just to make this worthwhile.
Just a word of warning, these functions might run slower than the longer versions since there is the overhead of Application.Run as well as the transfer mechanisms involved although Python can get the same flak. But if performance is not an issue, then this library is good for you and your sanity.
Quick Start
This is a chip project, so you can download this via Chip.ChipOnFromRepo «Fn» or if you want to install it via importing module. Just import these four modules in your project.
Dependency
- ArrayUtil.bas — Since xlfn is built-on ArrayUtil, this module is it’s only dependency as well as to build on the Map, Reduce and Filter using Arrays. It is recommended to get xlbutil to avoid this missing module definition
Core
- Fn.bas — The core module, this module creates and runs the pseudo functions described above via Fn.Invoke. Aside from the normal invokation, this allows the creation of composite pseudo functions that allow the functional concept of currying, closures and composition in a certain way.
- FnArrayUtil.bas — Not a true dependency but this module hosts all the core functions this module was built upon specially the promise of functional application.
Optional
- FnIterator.bas — A toy module to replicate iterators or generators from Python, it’s not practical to use than a while-loop but hey it’s nice to know.
- FnPredicate.bas — A set of pseudo predicate functions for common conditions
- FnFunction.bas — A set of pseudo functions that are useful for Map operations or whatnot
- FnOperator.bas — A set of pseudo operator functions or binary functions that encapsulate the common operators, useful for ZipWith like operations
And include in your project references the following.
- Microsoft Visual Basic for Applications Extensibility 5.3 — Any version would do but it has been tested with version 5.3
- Microsoft Scripting Runtime — Also make sure you enable Trust Access to the VBA project object model to allow this reference to work. This can be found in the Trust Center under Macro Settings
So to see if it’s working, run in the Intermediate Window or what I call the terminal.
You should see in the window output «Hello Fn: The Pseudo Functional Programming Library for VBA» in the intermediate window.
Composite Functions And More Functionality
We can stop with just Fn.Invoke and be happy with FnArrayUtil for the three major functions but we can go deeper and get a few more pieces of the functional power. Within the bounds of VBA, they are Currying, Composition, Closure and probably more. If you don’t know these concepts, I encourage you to check out the links.
A quick sample for each major C concept.
' Let's call this module MyModule again for reference ' Note: The arguments are wrapped in Array() rather than using Varargs since it complicates parameter and argument passing. Public Sub Curring() ' Let's curry the add operator Dim AddTwoFp as Variant AddTwoFp = Fn.Curry("MyModule.Add_", Array(2)) Debug.Print Fn.InvokeOneArg(AddTwoFp, 1) ' Outputs 3 Debug.Print Fn.InvokeTwoArgs("MyModule.Add_", 2, 1) ' Like above Dim AddTwoAndThreeFp as Variant AddTwoAndThreeFp = Fn.Curry(AddTwoFp, Array(3)) ' OR AddTwoAndThreeFp = Fn.Curry("MyModule.Add_", Array(2, 3)) Debug.Print Fn.InvokeNoArg(AddTwoAndThreeFp) ' Outputs 5 Debug.Print Fn.InvokeTwoArgs("MyModule.Add_", 2, 3) ' Like above End Sub Public Sub Add_(LVal as Variant, RVal as Variant) Fn.Result = (LVal + RVal) End Sub Public Sub Composition() ' Let's compose strings of functions to make this example better Dim PipelineFp as Variant PipelineFp = Fn.Compose(Array("MyModule.Format_", "MyModule.Negative_", "MyModule.Add_")) Debug.Print Fn.InvokeTwoArgs(PipelineFp, 2, 3) ' Outputs Value: -5 Debug.Print Fn.InvokeOneArg(MyModule.Format_", Fn.InvokeOneArg("MyModule.Negative_", Fn.InvokeTwoArgs("MyModule.Add_", 2, 3))) ' Same as above Debug.Print Composed(2, 3) ' Or simple like this defined normal function End Sub Public Sub Negative_(Val as Variant) Fn.Result = -1 * Val ' For safety purposes but -Val is okay End Sub Public Sub Format_(Val as Variant) Fn.Result = "Value: " & Val End Sub Public Function Composed(LVal as Variant, RVal as Variant) Composed = "Value: " & (-(LVal + RVal)) End Function Public Sub Closure() ' Let's replicate a counter generator for this example Dim CountFromTenFp as Variant CountFromTenFp = Closure_(10) Debug.Print Fn.InvokeNoArgs(CountFromTenFp) ' Outputs 10 Debug.Print Fn.InvokeNoArgs(CountFromTenFp) ' Outputs 11 Debug.Print Fn.InvokeNoArgs(CountFromTenFp) ' Outputs 12 End Sub Public Function Closure_(Start_ as Long) as Variant Closure_ = Fn.CreateLambda("MyModule.Counter_Fn", Empty, Empty, Start_) ' This creates a function with a closure variable of Start_ End Funciton Private Sub Counter_Fn(Optional Args as Variant = Empty) ' Optional Args is required when defining composite functions like this which uses Closure or PreArgs although we won't be using the arguments Fn.Result = Fn.Closure Fn.Closure = Fn.Closure + 1 End Sub
So if that small snippet got you interested, let’s talk about the mechanics of Composite Functions with the making of Fn.Curry.
So with Fn.Invoke setup, I wanted to curry a function, this means a function taking a function and an array of arguments and returning a function when invoked appends the preset arguments to the current arguments thus currying. Initially, the invokation mechanism only supported strings so there was a design concession of FnBuffer which is limited in scope and now removed. The final design solution was to allow a fake function pointer in the form of a four element array which can carry preset arguments and allow this function to use the preset arguments along with it’s invoked arguments. This fake function is created by Fn.CreateLambda which accepts the preset arguments and a function name that uses these arguments; that function is what I call as a composite function since it’s main idea is to invoke another function. Here is the code snippet for Fn.Curry to better explain the concept.
' This function sets the variables for the composite function to use Public Function Curry(MethodFp As Variant, PreArgs As Variant) As Variant ' MethodFp is the function to be curried and PreArgs is the array of arguments to be added to the original one Curry = CreateLambda(CURRY_METHOD, MethodFp, PreArgs, Empty) ' CURRY_METHOD = 'Fn.Curry_Fn' ' The last Empty parameter is the ClosureVars which this function doesn't need to use End Function ' This function defines the actual curry procedure ' The argument chaining is done through the line ArrayUtil.JoinArrays(Fn.PreArgs, Args) ' Note the properties Fn.NextFp and Fn.PreArgs which is MethodFp and PreArgs in the Curry definition is used here although they aren't defined locally. ' These properties are added before the function is called so that they can be used here. Private Sub Curry_Fn(Optional Args As Variant = Empty) ' Customary to add this check when dealing with array of arguments as the arguments itself If IsMissing(Args) Then _ Args = ArrayUtil.CreateEmptyArray() ' AssignResult_ is simply Fn.Result = Fn.Invoke(Fn.NextFp, ArrayUtil.JoinArrays(Fn.PreArgs, Args)) ' except that it also works for Object assignment. Basically an utility for object assignment AssignResult_ Fn.Invoke(Fn.NextFp, ArrayUtil.JoinArrays(Fn.PreArgs, Args)) End Sub
So this how currying was achieved. First define a function that sets the preset arguments, then define the actual function which uses thes variables. The actual defining function is suffixed with _Fn as convention as well as the function pointer variable is suffixed with Fp and is of type variant. These functions created by Fn.CreateLambda must accept an optional variant argument paramenter as well for invokation safety since that function can be invoked with or without arguments, it’s best to have it optional and just create a default when there is none. The function definition is expected to be private since it will be stored as a variable and reduces the clutter in the intellisense. Finally, one can define a private constant variable for the name of the composite function for refactoring as well as intellisense guide.
And most important of all since the function pointer is just a variant array, avoid modifying the pointer array since it is mutable and the function mechanism can be screwed up; however, you can modify if you know what you’re doing and can provide esoteric experimentation with this mechanism. But if you’re curious what the function pointer holds, these are the four element values.
- MethodFp — This is what the Fn.Invoke will actuall call, which is the defining function hopefully. Additionally this is also the implicit property Fn.ThisFp which can allow for recursive calls with Fn.Invoke, an example of this is defining Fibonacci with this framework.
- NextFp — This is the read-only property Fn.NextFp which is expected to be invoked in the function
- PreArgs — This is the read-only property Fn.PreArgs which was preset
- ClosureVars — This is both a read and write property Fn.Closure which allows state in these functions. Checkout the Counter_Fn is the major example above for how to set it.
One final piece of advice for this is that you should test these function first before actually using them. Since they don’t that have type safety or if the functions did not use the variables or follow the framework, it’s ideal to test the invokation and the return.
Here is a list of some notable composite functions defined in the library
- Fn.WithArgs — This initiall takes an array of arguments, then takes an function pointer and invokes the function with the array of arguments. Kinda like curry but it is designed to work with Fn.Map with an array of function pointers
- Fn.Decorate — A shorthand for Fn.Composite when just wrapping one function on another
- Fn.Unpack — This simulates Python’s tuple unpacking so when a function receives an array of arguments, this decoration will unpack the arguments correctly. Again this is for Fn.Map
- FnUtil.Memoize — A simple memoize toy implementation.
- FnUtil.Timeit — A decorator that times the function execution using Timer much like Python’s timeit.
In summary, this mechanism allows currying, composition and closure. You can checkout the test cases or explore the library to get a better view. But if you can define the function as a pure/leaf function or functions that don’t need Fn.CreateLambda to work the better. Actually, the less use of Fn.Invoke the better as it is faster and doesn’t add debugging complexity. Just remember that statically defined functions are better than composite or pseudo function, this library just supports these operations.
Recursion And Fn.ThisFp
This section describes a small snippet of how to do recursion with the pseudo functions. Let’s define Fibonacci Function here.
' The simple definition ' N is assumed to be non-negative Public Sub Fibonacci_(N as Long) If N < 3 Then Fn.Result = 1 Else Fn.Result = Fn.Invoke("Fibonacci_", N - 1) + Fn.Invoke("Fibonacci_", N - 2) End If End Sub
This definition is correct but the nagging part is the «Fibonacci_» string there. You can define a constant above to make it cleaner but is there a more exact way of defining this? Simply use Fn.ThisFp as seen in the correct code snippet
' The proper definition ' N is assumed to be non-negative Public Sub Fibonacci_(N as Long) If N < 3 Then Fn.Result = 1 Else ' Note Fn.ThisFp instead of "Fibonacci_" Fn.Result = Fn.Invoke(Fn.ThisFp, N - 1) + Fn.Invoke(Fn.ThisFp, N - 2) End If End Sub
And that’s it, nothing big. It’s a nice thing to see Java this or perhaps Python self as a reminder. The true technical nature of this is that it supports recursive composite functions where you just can’t put the name of the current function if it contains state variable although I doubt you’ll need this. To demonstrate, here is a snippet.
Public Sub NTimes(Fp as Variant, N as Long) NTimes = Fn.CreateLambda("NTimes_Fn", Fp, Empty, N) End Sub ' This can be done in a while loop but this just to demonstrate the fact. Private Sub NTimes_Fn(Optional Args as Variant = Empty) Fn.Invoke(Fn.NextFp) If Fn.Closure > 0 Then ' The way to do it is to invoke it again using Fn.ThisFp, note you can't use "NTimes_Fn" in this scenario since it won't remember the counter Fn.Closure = Fn.Closure - 1 ' This mutates the counter right before calling it again, be careful of StackOverflow Fn.InvokeNoArgs(Fn.ThisFp) End if End Sub Public Sub SayHello_() Debug.Print "Hello there" End Sub Public Sub Main() Dim FiveTimesFp as Variant FiveTimesFp = NTimes("SayHello_", 5) Fn.InvokeNoArgs(FiveTimesFp) ' Prints "Hello there" five times End Sub
Hopefully you won’t need this. Truly just a nice syntactic property to see.
Неявное пересечение использовалось в Excel уже много лет, но мало кто заботился об этом. Теперь, когда это больше не поведение по умолчанию в Excel 365, возникает много вопросов. Этот учебник призван дать ответы.
У вас возникает ощущение, что вы знаете о своих книгах все, а затем в начале ваших формул из ниоткуда появляется символ @. Что это значит? И как именно это работает? В двух словах, это неявный оператор пересечения, который отключает новое поведение массива по умолчанию для формулы и сообщает Excel, что нужно вернуть одно значение. Для более подробной информации, пожалуйста, продолжайте читать.
Неявное пересечение в Excel означает сокращение нескольких значений до одного значения. Обычно это происходит, когда в формулу передается массив или диапазон, который должен выводить только одно значение в одной ячейке.
Неявное пересечение в Excel 2019 — 2000
В традиционном Excel неявное пересечение является поведением по умолчанию. Он выполняется в фоновом режиме для всех формул. Логика неявного пересечения выглядит следующим образом:
- Если формула возвращает одно значение, верните это значение (на самом деле неявное пересечение в этом случае ничего не делает).
- В случае диапазона используйте значение из ячейки в той же строке или столбце, что и формула.
- В случае массива используйте верхнее левое значение.
Например, при умножении двух столбцов чисел Excel выбирает только одно число из каждого столбца в той же строке, где находится формула, и выводит результат только в одну ячейку (в нашем случае D2):
=В2:В5*С2:С5
Чтобы умножить числа в других ячейках, нужно скопировать формулу вниз.
Чтобы отключить неявное пересечение, вы должны ввести формулу массива с помощью Ctrl + Shift + Enter (поэтому традиционные формулы массива иногда называют формулы СПП). Это четко указывает Excel на необходимость обработки нескольких входных значений в виде диапазонов или массивов.
В нашем случае выберите ячейки D2:D5, введите приведенную выше формулу и подтвердите ее, нажав одновременно клавиши Ctrl + Shift + Enter. Как только вы это сделаете, формула будет заключена в {фигурные скобки}, указывая на то, что это формула массива. В результате числа в каждой строке перемножаются сразу:
Неявное пересечение в Excel 365
Внедрение динамических массивов изменило поведение по умолчанию всех формул в Excel 365. Теперь любая формула, которая потенциально может давать несколько результатов, автоматически переносит их на лист. Это делает неявное пересечение ненужным, и оно больше не запускается по умолчанию. По этой причине Excel 365 иногда называют динамический массив Excel или же ДА Excel.
Здесь все диапазоны умножаются на обычную формулу, которая вводится только в самую верхнюю ячейку (D2):
=В2:В5*С2:С5
В результате получается диапазон разливов, состоящий из 4 ячеек:
Если вы хотите, чтобы формула возвращала только одно значение, вам нужно явно включить неявный перехват. Для этого они ввели специальный оператор, и в следующем разделе вы найдете полную информацию о нем.
Оператор неявного пересечения Excel — символ @
Неявный оператор пересечения был введен в Excel 365, чтобы предотвратить поведение динамического массива по умолчанию. Если вы хотите, чтобы формула возвращала только одно значение, поставьте @ перед именем функции (или перед определенным диапазоном или массивом внутри формулы), и она будет вести себя как обычная формула без массива в додинамических версиях.
Например:
=@B2:B5*@C2:C5
Примечание. Оператор неявного пересечения поддерживается только в подписках Microsoft 365. Если вы попытаетесь добавить знак @ в более старых версиях, он будет автоматически удален после завершения формулы.
Почему @ добавляется к старым формулам?
В Excel 365 вы можете заметить символ @, добавленный к некоторым вашим формулам при открытии книги, созданной в более старой версии. По большей части это делается для того, чтобы заставить формулу вести себя так же, как в исходной версии, в которой она была создана. Другими словами, если формула возвращала одно значение в более старой версии, но возвращала несколько результатов в Excel 365, она будет автоматически иметь префикс @, чтобы деактивировать поведение массива.
Обычно оператор пересечения вставляется перед функцией, которая может возвращать многоячеечные массивы или диапазоны, такие как OFFSET, INDEX или определяемые пользователем функции.
Например, следующая формула, созданная в предварительно динамическом Excel:
=ИНДЕКС(B2:C5,,F1)
примет следующий вид в динамическом массиве Excel:
=@ИНДЕКС(B2:C5,,F1)
Причина в том, что без оператора @ формула вернет все значения из C2:C5, потому что row_num аргумент функции ИНДЕКС опущен. Чтобы обеспечить согласованное поведение во всех версиях, становится очевидным ранее незаметное неявное пересечение. Пожалуйста, сравните результаты:
В случае, если функция с потенциальным многоячеечным выводом вложена в другую функцию, которая может обрабатывать массивы и выводить один результат (например, СУММ, СЧЁТ, СРЗНАЧ и т. д.), то нет причин запускать неявное пересечение, и формула переносится в динамический Excel как есть без добавления знака @. Например:
=СРЗНАЧ(ИНДЕКС(B2:C5,,F1))
Могу ли я удалить символ @ из своих формул?
Что вы можете. Excel выполняет преобразование формулы только один раз. Если оператор @ нарушает или негативно меняет поведение ваших формул, вы можете удалить @ вручную, и он больше не появится после сохранения книги.
Каковы последствия удаления оператора неявного пересечения? В зависимости от того, что возвращает часть формулы, следующая за знаком @, возможны три результата:
- Если возвращается одно значение, изменений не будет.
- Если массив возвращается, он будет распространяться на соседние ячейки.
- Если массив возвращается, но пустых ячеек недостаточно для отображения всех значений, возникает ошибка #SPILL.
Зачем использовать оператор @ в Excel 365?
Как уже упоминалось, Excel для Microsoft 365 по умолчанию обрабатывает все формулы как формулы массива, и вам не нужно нажимать Ctrl + Shift + Enter, как вы делали это в предыдущих версиях. Если вы хотите отключить поведение массива, вставьте неявный оператор пересечения.
Пример 1. Избавьтесь от #РАЗЛИВ! ошибка
Очень распространенный сценарий — предотвращение или исправление ошибок #SPILL. Если вам удобно ссылаться на целые столбцы (что вообще не очень хорошая идея, потому что тормозит Excel), но тем не менее такая формула будет нормально работать в преддинамических версиях:
=ВПР(А:А, Г:Д, 2, ЛОЖЬ)
В динамическом Excel это приведет к ошибке #SPILL, поскольку недостаточно места для отображения почти 1,05 миллиона результатов.
Добавление @ перед аргументом lookup_value решает проблему:
=ВПР(@А:А, Г:Д, 2, ЛОЖЬ)
Когда Excel предвидит, что формула может выйти за пределы рабочего листа, он предложит исправление, и вам будет разумно его принять:
Пример 2. Заставьте формулу работать правильно в старых версиях Excel
Если вы используете подписку на Microsoft 365 и делитесь своими файлами с кем-то, кто использует более старую версию, важно обеспечить согласованное поведение формулы для всех.
Предположим, вы написали эту формулу динамического массива в Excel 365:
=В2:В5*С2:С5
В более старых версиях он будет преобразован в устаревшую формулу массива CSE:
{=B2:B5*C2:C5}
и вернуть диапазон значений в обоих случаях:
Если вы хотите вывести только один результат, добавьте @ перед каждым выражением, а затем скопируйте формулу в необходимое количество ячеек (чтобы сохранить диапазоны без изменений, не забудьте заблокировать их абсолютными ссылками на ячейки):
=@$B$2:$B$5*@$C$2:$C$5
В старых версиях Excel символ @ будет автоматически удален, и формула примет обычный вид:
=$B$2:$B$5*$C$2:$C$5
Чего не следует делать, так это смешивать в одной формуле неявное пересечение и вычисление массива! Например, если вы попытаетесь ввести что-то подобное в Excel 365:
=@B2:B5*C2:C5
Вы будете уведомлены, что такая формула не поддерживается в более старых версиях:
Если вы отклоните предложенный вариант, смешанная формула будет принята и принесет некоторые результаты (хотя они могут быть не такими, как вы ожидали). Но когда вы открываете эту формулу в предварительно динамическом Excel, функция _xlfn.SINGLE появится вместо неявного оператора пересечения:
=_xlfn.SINGLE(B2:B5)*C2:C5
Когда эта формула оценивается старой версией Excel, #ИМЯ! будет возвращена ошибка.
Неявное пересечение в таблицах Excel
Вообще говоря, поведение неявного пересечения в таблицах соответствует вашей версии Excel.
В Excel 2019 и более ранних версиях вы можете ссылаться на весь столбец, и формула будет разрешаться в одну ячейку в текущей строке.
Например, эта формула успешно умножает числа в Цена а также Кол-во столбцы:
знак равно[Price]*[Qty.]
Несмотря на то, что он относится ко всем столбцам, преддинамический Excel по-прежнему работает с отдельными значениями на уровне строки.
В Excel 365 этот подход не работает, так как неявное пересечение отключено по умолчанию. Поскольку формула возвращает несколько значений, и Excel не может поместить их все в таблицу, она предложит добавить к именам столбцов префикс с символом @:
Если у вас есть опыт работы со ссылками на таблицы, этот синтаксис должен быть вам знаком — символ @ указывает, что формула будет обрабатывать значения из столбцов. Цена а также Кол-во в том же ряду.
знак равно[@Price]*[@[Qty.]]
И это будет хорошо работать во всех версиях:
Кончик. Если вы намерены использовать функцию динамического массива для вычисления данных таблицы, обязательно поместите формулу вне таблицы, поскольку динамические массивы внутри таблиц не поддерживаются.
Вот как работает неявное пересечение в Excel. Я благодарю вас за чтение и надеюсь увидеть вас в нашем блоге на следующей неделе!