TOCOL flattens. It takes an m × n array and returns a single column containing its
elements in a chosen traversal order, optionally dropping some of them.
The traversal is the substantive parameter. With scan_by_column false or omitted, the array
is read by row — left to right along row 1, then row 2, and so on, which is row-major
order. With scan_by_column true, it is read by column — top to bottom down column 1, then
column 2. For the array {1,2;3,4} those give {1;2;3;4} and {1;3;2;4} respectively.
The ignore argument then removes categories of element before the column is assembled:
ignore
Documented meaning
0
Keep all values (default)
1
Ignore blanks
2
Ignore errors
3
Ignore blanks and errors
The result length is therefore m · n minus whatever was dropped — the one place in this
family where the output size is not a pure function of the input's shape.
TOCOL(range, 1) is, in practice, the modern answer to "give me the non-empty values of this
rectangle as a list", which is why it turns up in UNIQUE, SORT and TEXTJOIN pipelines far
more often than its documentation suggests.
Arguments
Microsoft documents TOCOL(array, [ignore], [scan_by_column]).
array — required. The array or reference to flatten.
ignore — optional, default 0. Takes the four values above. Note that it is a small
integer code, not a logical: TOCOL(A1:C9, TRUE) coerces to 1 and means "ignore blanks",
which happens to be a reasonable request but is not what the writer of TRUE was thinking.
scan_by_column — optional, default FALSE. A logical. When omitted or FALSE, the array
is scanned by row; when TRUE, by column.
The two optional arguments are the ones readers swap, because both are small and both are
"options". TOCOL(A, 1) ignores blanks; TOCOL(A, , 1) scans by column. The first is a
filter, the second a traversal order, and neither is an error, so a swap produces a
correct-looking column with the wrong contents or the wrong order.
Try it
Quirks
Result and edge cases
The return kind is a single-column array.
The result can be empty.TOCOL(range, 3) over a range of only blanks and errors leaves
nothing. The Excel convention for an empty array result is #CALC!
(the value universe), and TOCOL uses it:
TOCOL({#N/A},2) drops the error, has nothing left, and is #CALC! (FN-HSTACK-001).
What counts as "blank". Whether ignore1 drops empty cells only, or also empty text
"", is the question this function turns on in practice — a column produced by a formula
chain is usually full of "", not of empty cells. The documentation says "blanks" and does
not disambiguate; the Handbook has not verified it.
Ignoring errors removes them entirely; it does not replace them. The result is shorter,
which means positions no longer correspond to the source. A direct error is not an element
and is not ignored: TOCOL(#N/A,2) is #N/A (FN-HSTACK-001).
A single-element result stays an array. See the TAKE page for the probes that make that
distinction observable.
Dynamic-array publication and #SPILL! are host-side adaptation, not TOCOL semantics.
Errors
Documented by Microsoft on the TOCOL page:
Error
Documented condition
#VALUE!
An array constant containing one or more numbers that are not whole numbers
#NUM!
array is too large
The first of those is worth flagging as unusual: it is stated on Microsoft's page, and it does
not obviously describe a flattening operation, whose result should not care whether its
elements are integers. The Handbook records it as documented and does not attempt to explain
it; confirming what it actually refers to is one of the open probes below.
A direct error stops these array functions; the same error in an array or cell is an element
An error written directly as an argument of these functions is the answer for the whole call. It is not placed in the result: HSTACK(1,#VALUE!) is #VALUE!, not a row holding 1 and an error, and TAKE(#N/A,0) is #N/A. With MAP the LAMBDA does not run at all: MAP(NA(),LAMBDA(xx,IFERROR(xx,3))) is #N/A. The same error inside an array, or in a referenced cell, is an ordinary element: MAP({#N/A},LAMBDA(xx,3)) is 3, and HSTACK(Data!C1,{1;2}) with #N/A in Data!C1 is a 2 by 2 array with #N/A in its first column. TOCOL and TOROW show the difference with ignore 2: TOCOL(#N/A,2) is #N/A, while TOCOL({#N/A},2) drops the error, has nothing left, and is #CALC!. EXPAND is an exception on the cell side: EXPAND(Data!C1,2,2,"pad") is #N/A for the whole call. BYROW and BYCOL check the direct error first too: BYROW(#N/A,#VALUE!) is #N/A, while BYROW({#N/A},2), where 2 is not a LAMBDA, is #VALUE!.
Formula
Excel
Mathematical value
=HSTACK(1,#VALUE!) Excel 16.0.20527.20088 Current Channel, Windows 64-bit (NT 10.0.26200), x86-64, AMD Ryzen 7 4800H, en-ZAInputs and reference value
Typed formula.
#VALUE!
—
=TAKE(#N/A,0) Excel 16.0.20527.20088 Current Channel, Windows 64-bit (NT 10.0.26200), x86-64, AMD Ryzen 7 4800H, en-ZAInputs and reference value
Typed formula.
#N/A
—
=MAP(NA(),LAMBDA(xx,IFERROR(xx,3))) Excel 16.0.20527.20088 Current Channel, Windows 64-bit (NT 10.0.26200), x86-64, AMD Ryzen 7 4800H, en-ZAInputs and reference value
Typed formula.
#N/A
—
=MAP({#N/A},LAMBDA(xx,3)) Excel 16.0.20527.20088 Current Channel, Windows 64-bit (NT 10.0.26200), x86-64, AMD Ryzen 7 4800H, en-ZAInputs and reference value
Typed formula.
3 0x4008000000000000
—
=HSTACK(Data!C1,{1;2}) Excel 16.0.20527.20088 Current Channel, Windows 64-bit (NT 10.0.26200), x86-64, AMD Ryzen 7 4800H, en-ZAInputs and reference value
Number supplied through a cell.
Data!C1: #N/A
{#N/A,1;#N/A,2}
—
=TOCOL(#N/A,2) Excel 16.0.20527.20088 Current Channel, Windows 64-bit (NT 10.0.26200), x86-64, AMD Ryzen 7 4800H, en-ZAInputs and reference value
Typed formula.
#N/A
—
=TOCOL({#N/A},2) Excel 16.0.20527.20088 Current Channel, Windows 64-bit (NT 10.0.26200), x86-64, AMD Ryzen 7 4800H, en-ZAInputs and reference value
Typed formula.
#CALC!
—
=EXPAND(Data!C1,2,2,"pad") Excel 16.0.20527.20088 Current Channel, Windows 64-bit (NT 10.0.26200), x86-64, AMD Ryzen 7 4800H, en-ZAInputs and reference value
Number supplied through a cell.
Data!C1: #N/A
#N/A
—
=BYROW(#N/A,#VALUE!) Excel 16.0.20527.20088 Current Channel, Windows 64-bit (NT 10.0.26200), x86-64, AMD Ryzen 7 4800H, en-ZAInputs and reference value
Typed formula.
#N/A
—
=BYROW({#N/A},2) Excel 16.0.20527.20088 Current Channel, Windows 64-bit (NT 10.0.26200), x86-64, AMD Ryzen 7 4800H, en-ZAInputs and reference value
Two orthogonal parameters: what to skip, and in what order to walk. Implementing ignore as
a post-filter on an already-built column is correct only if the traversal order was applied
first — the two commute here, but only because filtering is order-preserving.
ignore is a code, not a flag. Values outside 0..3 need a decided outcome.
The blank definition — empty cell versus empty string versus a formula returning "" — must
be stated. It is the single most consequential ambiguity in this function.
An empty result is a real case with a specific outcome, not an edge to leave undefined.
Scalars and 1×1 arrays flatten to a one-element column, which must stay array-shaped.
Rust code
Show the CalcFunc source of this function
Quoted from the public repository DnaCalc/DnaCalc, crates calc-func and calc-fml, at commit 9e1884369a67. Comments are the source's own. A kernel shared with other functions appears once, on its module page.
No implementation has been published with a Handbook test suite for this function.
Version differences
No comparison between specific Excel builds is recorded here yet. This does not establish that all builds behave alike.
Excel 16.0.20527.20088
Windows 64-bit (NT 10.0.26200), x86-64, AMD Ryzen 7 4800H, en-ZA
=TOCOL(#N/A,2) returned #N/A. =TOCOL({#N/A},2) returned #CALC!. Inputs were supplied through formula literals. These are controls from this environment, not a same-input comparison with another build.
Observed formulas and results
=TOCOL(#N/A,2) → #N/A(formula-literal)
=TOCOL({#N/A},2) → #CALC!(formula-literal)
Alternatives
Relationships
TOROW is the transpose: the same flattening with the same ignore and
scan_by_column vocabulary, producing a single row. TOCOL(x, i, s) equals
TRANSPOSE(TOROW(x, i, s)).
WRAPCOLS / WRAPROWS are the inverse: a vector back to a rectangle.
TRANSPOSE exchanges the axes without flattening.
FILTER removes whole rows by predicate; TOCOL's ignore removes individual elements
by kind. They are not substitutes.
TRIMRANGE removes the blank margin of a range; TOCOL(…, 1) removes blanks
everywhere, including interior ones, and destroys the two-dimensional structure while doing
it.
VSTACK concatenates while preserving structure; flattening a stack is a common
composition (TOCOL(VSTACK(a, b), 1)).