Available in:Excel 2024 or later (Works in Excel 2024, every later version, Microsoft 365 and Excel for the web)Category:Dynamic arrays

TOROW

NAAR.RIJ in Dutch Excel

Turns a range or array of any shape into one row, reading it row by row or column by column and optionally skipping blanks and errors.

Difficulty rating 3 of 5. The formula is short, but the order in which cells are read, the ignore codes for blanks and errors, and the spill into a row all change the result without announcing it.

Last updated: 13 October 2026

See the worked examples

Sheet excerpt: E2 holds the formula
RowABCDEFGHIJ
1SanneTomAisha
225-110125-110425-110925-1101=TOROW(A2:C3)=TOROW(A2:C3)25-110425-110925-110225-110525-1110
325-110225-110525-1110
Formula cell (E2)Spilled result
=TOROW(A2:C3)
=TOROW(A2:C3)

What TOROW does and when to use it

What it does: it lays every value of a block of cells out in one row, for example the sampled invoices of three columns on one line.

When to use it: when a grid has to become a list: as input for TEXTJOIN or UNIQUE, for a duplicate test across several columns, or as a header row built from a column of names. The row spills to the right. It is the horizontal twin of TOCOL. To swap rows and columns and keep the grid shape, use TRANSPOSE.

Two main gains:

  • Stays live: Paste Special with Transpose is a one-off copy, while the row updates when the source changes.
  • Skips blanks and errors: ignore leaves out empty cells, errors or both.

How Excel evaluates it

Excel first evaluates array, which can be a range or the result of another formula. It then checks ignore:

  • 0 keeps everything
  • 1 drops blank cells
  • 2 drops errors
  • 3 drops blank cells and errors

It reads the remaining cells in the order set by scan_by_column: across each row by default, or down each column when you pass TRUE. All items are placed in a single row, one per column, spilling to the right of the formula cell. If a cell in that spill area is occupied, you get #SPILL! instead.

Watch out: With the default ignore of 0, a blank cell in the grid comes back as a 0 in the row.

Mental model

Cutting a grid of tiles into strips and gluing the strips end to end in one long line: scan_by_column decides whether you cut along the rows or along the columns.

Terms used on this page: spill, array, range, cell

TOROW(array, [ignore], [scan_by_column])
TOROW(array; [ignore]; [scan_by_column])
Arguments
ArgumentTypeMeaningDefault
arrayRequiredThe range or array to flatten into one row.
ignoreOptionalWhat to skip: 0 nothing, 1 blanks, 2 errors, 3 blanks and errors.0
scan_by_columnOptionalFALSE reads row by row (default); TRUE reads column by column.FALSE

Return value:A single row holding every kept value of array, in the order it was read

Formulas use commas (,) between arguments, as in English Excel. Formulas use semicolons (;) between arguments, as in Dutch Excel. Formulas use commas (,) between arguments, as in English Excel; Dutch Excel uses semicolons (;).

Worked examples

Beginner

Put a sample drawn in three columns on one row

At Veldhuis Installatie BV your team drew a sample of purchase invoices. Sanne, Tom and Aisha each pasted their selection under their own name, so the sample sits in a grid of three columns. For the workpaper header you want all six invoice numbers on a single row.

Sheet excerpt: E2 holds the formula
RowABCDEFGHIJK
1SanneTomAisha
225-110125-110425-110925-1101=TOROW(A2:C3)=TOROW(A2:C3)25-110425-110925-110225-110525-1110
325-110225-110525-1110
4
Formula cell (E2)Spilled result

Formula in E2

=TOROW(A2:C3)
=TOROW(A2:C3)

Result: 25-1101 | 25-1104 | 25-1109 | 25-1102 | 25-1105 | 25-111025-1101 | 25-1104 | 25-1109 | 25-1102 | 25-1105 | 25-1110

Step by step
  1. The array is A2:C3: 2 rows and 3 columns, so 6 cells. The header row 1 is not part of it. ignore and scan_by_column are left out, so every cell is kept and the grid is read row by row.
  2. The first row of the grid, left to right, gives 25-1101, 25-1104 and 25-1109.
  3. The second row gives 25-1102, 25-1105 and 25-1110.
  4. The 6 items are placed side by side, so the result spills from E2 to J2: 1 row and 6 columns. Counted off, the 4th item is 25-1102, because it is the first value of row 2 and not the 4th value of column A.
  5. Change B3 to 25-1199 and the 5th item in the row changes with it, because the row is a live view of the grid and not a copy.

Watch out: If anything is typed in F2:J2, the formula shows #SPILL! instead of the row. Keep the cells to the right of a TOROW empty.

More on this example: why it works, 1 variation

Why it works

TOROW visits the cells in a fixed order and writes each one into the next column of a single row. With no optional arguments the order is the one you read a page in: left to right, then down.

Variations

=TOROW(A2:C3, 0, TRUE)
=TOROW(A2:C3; 0; TRUE)

Read column by column instead: Sanne's two invoices first, then Tom's, then Aisha's. Prefer it when the columns are meaningful groups.

Intermediate

Flatten bank reconciling items and skip the empty cells

The client's bank reconciliation lists reconciling items in a grid: one column per bank account, with gaps where an account has no item on that line. You want one row with only the amounts, so you can count the items and compare their sum with the difference to explain.

A plain flattening would add a 0 for every gap.

Sheet excerpt: E2 holds the formula
RowABCDEFGHIJK
1Current accountSavings accountForeign currency
2€1,250.00€ 1.250,00€480.00€ 480,00€1,250.00€ 1.250,00=TOROW(A2:C5, 1)=TOROW(A2:C5; 1)€480.00€ 480,00€3,000.00€ 3.000,00-€725.00€ -725,00€1,900.00€ 1.900,00€615.00€ 615,00
3€3,000.00€ 3.000,00
4-€725.00€ -725,00€1,900.00€ 1.900,00
5€615.00€ 615,00
6
Formula cell (E2)Spilled result

Formula in E2

=TOROW(A2:C5, 1)
=TOROW(A2:C5; 1)

Result: €1,250.00 | €480.00 | €3,000.00 | -€725.00 | €1,900.00 | €615.00€ 1.250,00 | € 480,00 | € 3.000,00 | € -725,00 | € 1.900,00 | € 615,00

Step by step
  1. The array is A2:C5: 4 rows and 3 columns, 12 cells, of which 6 are blank (B2, A3, C3, B4, A5, B5). ignore is 1, so blanks are dropped.
  2. Row 2 left to right: 1250, blank (skipped), 480. Row 3: blank, 3000, blank, which leaves 3000.
  3. Row 4: -725, blank, 1900. Row 5: blank, blank, 615, which leaves 615.
  4. Six values remain and spill from E2 to J2: 1250, 480, 3000, -725, 1900, 615. Their sum is 1250 + 480 + 3000 - 725 + 1900 + 615 = 6520.
  5. Without the 1, the same formula would return 12 items, because each of the 6 blanks comes back as 0: 1250, 0, 480, 0, 3000, 0, -725, 0, 1900, 0, 0, 615. The sum stays 6520, but a count of the row would say 12 items instead of 6.

Watch out: A cell that looks empty but holds a space or a formula returning an empty text is not blank for ignore 1. It stays in the row as text. If the count is higher than the number of visible items, check those cells with ISBLANK.

More on this example: why it works, 1 variation

Why it works

ignore filters while the cells are read, before the row is built, so the row closes up over the gaps. The negative item -725 is kept because it is a real value; ignore 1 removes only cells that are empty, not zeros you typed.

Variations

=TOROW(A2:C5, 1, TRUE)
=TOROW(A2:C5; 1; TRUE)

Same items grouped per bank account: 1250, -725, 3000, 480, 1900, 615. Prefer it when you want to see each account's items together.

Advanced

List invoices to confirm in one line, grouped by quarter

From the receivables list of Veldhuis Installatie BV you select every invoice of at least the confirmation threshold in H1, to put in one cell of the confirmation request log. Invoice numbers per quarter sit in B:C and the amounts in D:E.

You want them listed quarter by quarter, so the Q3 invoices come before the Q4 invoices. Invoices below the threshold must not appear.

Sheet excerpt: G3 holds the formula
RowABCDEFGHI
1CustomerInvoice Q3Invoice Q4Amount Q3Amount Q4Confirm from2000020000
2Kaya Design BV25-201125-2087€18,400.00€ 18.400,00€31,250.00€ 31.250,00
3Molenaar Bouw BV25-2014€42,000.00€ 42.000,0025-2014, 25-2019, 25-2087, 25-2101, 25-2105=TEXTJOIN(", ", TRUE, TOROW(IF(D2:E6>=H1, B2:C6, NA()), 2, TRUE))=TEXTJOIN(", "; TRUE; TOROW(IF(D2:E6>=H1; B2:C6; NA()); 2; TRUE))
4Van Dijk Transport BV25-201925-2093€27,500.00€ 27.500,00€9,800.00€ 9.800,00
5Hendriks Metaal BV25-2101€20,000.00€ 20.000,00
6Smits Bouw BV25-202425-2105€6,200.00€ 6.200,00€55,400.00€ 55.400,00
7
Formula cell (G3)Input

Formula in G3

=TEXTJOIN(", ", TRUE, TOROW(IF(D2:E6>=H1, B2:C6, NA()), 2, TRUE))
=TEXTJOIN(", "; TRUE; TOROW(IF(D2:E6>=H1; B2:C6; NA()); 2; TRUE))

Result: 25-2014, 25-2019, 25-2087, 25-2101, 25-2105

Step by step
  1. Inside out, first the test D2:E6>=H1 with H1 = 20000.

    Column D: 18400 FALSE, 42000 TRUE, 27500 TRUE, blank FALSE (counts as 0), 6200 FALSE. Column E: 31250 TRUE, blank FALSE, 9800 FALSE, 20000 TRUE (equal counts, because of >=), 55400 TRUE.

  2. IF replaces each TRUE with the invoice number at the same position in B2:C6 and each FALSE with #N/A. The grid becomes:

    • row 2 is #N/A and 25-2087
    • row 3 is 25-2014 and #N/A
    • row 4 is 25-2019 and #N/A
    • row 5 is #N/A and 25-2101
    • row 6 is #N/A and 25-2105
  3. TOROW reads that grid column by column because scan_by_column is TRUE. First column: #N/A, 25-2014, 25-2019, #N/A, #N/A. Second column: 25-2087, #N/A, #N/A, 25-2101, 25-2105.
  4. ignore is 2, so the five errors are dropped and the row 25-2014, 25-2019, 25-2087, 25-2101, 25-2105 remains.
  5. TEXTJOIN glues the five items together with a comma and a space between them: 25-2014, 25-2019, 25-2087, 25-2101, 25-2105. The result is one text in G3.
  6. Raise H1 to 30000: only 42000, 31250 and 55400 qualify, and G3 becomes 25-2014, 25-2087, 25-2105.

Watch out: Silent error: if a large amount has no invoice number (blank in B or C), IF returns 0 for that position and 0 appears in the text. Compare the number of items with a COUNTIF on the amounts.

More on this example: why it works, 1 more pitfall, 2 variations

Why it works

IF over a whole grid keeps the grid's shape, so TOROW can flatten it in one go, and the errors from NA() act as 'skip this one' markers that ignore 2 removes. scan_by_column then sets the order to quarter by quarter.

TEXTJOIN alone would pass the errors on, so the flattening with error removal is what makes the join work.

More to watch out for

  • Leave ignore at 0 and the five #N/A values stay in the row, so TEXTJOIN returns #N/A and no list at all.

Variations

=TEXTJOIN(", ", TRUE, TOROW(IF(D2:E6>=H1, B2:C6, NA()), 2))
=TEXTJOIN(", "; TRUE; TOROW(IF(D2:E6>=H1; B2:C6; NA()); 2))

Without scan_by_column the list runs customer by customer: 25-2087, 25-2014, 25-2019, 25-2101, 25-2105. Prefer it when the customer order matters more than the quarter.

=TEXTJOIN(", ", TRUE, IF(D2:E6>=H1, B2:C6, ""))
=TEXTJOIN(", "; TRUE; IF(D2:E6>=H1; B2:C6; ""))

Shorter: empty texts instead of errors, which TEXTJOIN skips by itself. It reads row by row only, so use TOROW when you need the column order or the grid already contains errors.

Master

Find invoices paid in more than one payment file

For the duplicate payment test at Veldhuis Installatie BV you received three weekly payment files, pasted next to each other in columns A to C. Files differ in length, so the shorter ones end in blanks.

You want the invoice numbers that occur more than once anywhere in the grid, as a row for your workpaper, with a message when there are none.

Sheet excerpt: E2 holds the formula
RowABCDEFGH
1Payment file week 40Payment file week 41Payment file week 42
225-310125-310325-310425-3105=LET( paid, TOROW(A2:C7, 1), distinct, UNIQUE(paid, TRUE), once, UNIQUE(paid, TRUE, TRUE), FILTER(distinct, ISNA(XMATCH(distinct, once)), "No duplicate payments") )=LET( paid; TOROW(A2:C7; 1); distinct; UNIQUE(paid; TRUE); once; UNIQUE(paid; TRUE; TRUE); FILTER(distinct; ISNA(XMATCH(distinct; once)); "No duplicate payments") )25-310725-3110
325-310225-310525-3107
425-310525-310825-3109
525-310725-311025-3105
625-3110
725-3112
8
Formula cell (E2)Spilled result

Formula in E2

=LET(
  paid, TOROW(A2:C7, 1),
  distinct, UNIQUE(paid, TRUE),
  once, UNIQUE(paid, TRUE, TRUE),
  FILTER(distinct, ISNA(XMATCH(distinct, once)), "No duplicate payments")
)
=LET(
  paid; TOROW(A2:C7; 1);
  distinct; UNIQUE(paid; TRUE);
  once; UNIQUE(paid; TRUE; TRUE);
  FILTER(distinct; ISNA(XMATCH(distinct; once)); "No duplicate payments")
)

Result: 25-3105 | 25-3107 | 25-311025-3105 | 25-3107 | 25-3110

Step by step
  1. paid is TOROW(A2:C7, 1): 18 cells, of which 4 are blank (B6, C6, B7, C7). Read row by row with the blanks skipped, it holds 14 items: 25-3101, 25-3103, 25-3104, 25-3102, 25-3105, 25-3107, 25-3105, 25-3108, 25-3109, 25-3107, 25-3110, 25-3105, 25-3110, 25-3112.
  2. distinct is UNIQUE(paid, TRUE). by_col TRUE is needed because paid is a row. It keeps each invoice once, in order of first appearance: 25-3101, 25-3103, 25-3104, 25-3102, 25-3105, 25-3107, 25-3108, 25-3109, 25-3110, 25-3112. That is 10 invoices.
  3. once is UNIQUE(paid, TRUE, TRUE), with exactly_once TRUE: only invoices that occur a single time. 25-3105 occurs 3 times, 25-3107 twice and 25-3110 twice, so 7 invoices remain: 25-3101, 25-3103, 25-3104, 25-3102, 25-3108, 25-3109, 25-3112. Check: 10 distinct = 7 once + 3 repeated.
  4. XMATCH(distinct, once) looks up each of the 10 distinct invoices in once. For the 7 singles it returns a position, for 25-3105, 25-3107 and 25-3110 it returns #N/A. ISNA turns that into TRUE only for those three: FALSE for the first four, TRUE for 25-3105, TRUE for 25-3107, FALSE, FALSE, TRUE for 25-3110, FALSE for 25-3112.
  5. FILTER receives distinct and a row of 10 TRUE/FALSE values of the same width, so it keeps columns: 25-3105, 25-3107 and 25-3110. The result spills from E2 to G2.
  6. Clear A4, A5, A6 and C5, so every invoice occurs once: once then equals distinct, ISNA is FALSE everywhere, FILTER finds no TRUE and E2 shows No duplicate payments.

Watch out: The mirror-image mistake is leaving ignore at 0. The 4 blanks then come back as four 0 values, UNIQUE counts 0 four times, and the result gets a fourth hit, 0, next to the three real duplicates. It looks like a plausible extra finding.

More on this example: why it works, 2 more pitfalls, 1 variation

Why it works

UNIQUE and FILTER see a grid as separate rows and columns, so a test across the whole grid needs it in one dimension first, and TOROW with ignore 1 does that and drops the padding blanks.

Do not use this when the invoice numbers sit in one column: UNIQUE or COUNTIF work there directly, and the LET adds nothing. An alternative that works in every Excel version is a helper grid with =COUNTIF($A$2:$C$7, A2)>1 and conditional formatting; it marks the duplicates in place but does not produce a list.

More to watch out for

  • An invoice number exported with a trailing space, "25-3105 ", counts as a different invoice and the duplicate is missed without any error. Wrap the flattening in TRIM: TRIM(TOROW(A2:C7, 1)).
  • If every invoice occurs more than once, UNIQUE(paid, TRUE, TRUE) finds nothing and returns #CALC!. XMATCH then returns #CALC! for every item, ISNA of #CALC! is FALSE, so FILTER keeps nothing and shows the no-duplicates message although every invoice is a duplicate.

    That is the dangerous part. Check this case, or guard the once list, for example by comparing ROWS of distinct with the count of duplicates.

Variations

=LET(
  paid, TOROW(A2:C7, 1),
  SORT(UNIQUE(FILTER(paid, ISNA(XMATCH(paid, UNIQUE(paid, TRUE, TRUE)))), TRUE), 1, 1, TRUE)
)
=LET(
  paid; TOROW(A2:C7; 1);
  SORT(UNIQUE(FILTER(paid; ISNA(XMATCH(paid; UNIQUE(paid; TRUE; TRUE)))); TRUE); 1; 1; TRUE)
)

Sorted in ascending order and without the none message. It filters paid directly, so repeated hits are removed by an extra UNIQUE; use it when you want the list in invoice order.

Common mistakes

Common mistakes
SymptomCauseFix
Unexpected zeros and a count that is too highThe row contains zeros you did not expect, and a count of the items is too high.Pass 1 to skip blanks, or 3 to skip blanks and errors.
The items come out in an unexpected orderThe items come out in a different order than you read the grid, so the third item is not the third value in the first column.TOROW reads row by row unless told otherwise. Pass TRUE as scan_by_column to read down the first column, then the second.
#N/A in a TEXTJOIN or SUM around the rowErrors such as #N/A in the grid end up in the row, and a TEXTJOIN or SUM around it returns #N/A as well.ignore 1 skips only blanks. Use 2 to skip errors or 3 to skip both. Only do this when the errors mean 'no value', not when they signal a real problem.
#SPILL! although the formula is correctThe result is #SPILL! even though the formula is correct.Something sits in the cells to the right of the formula that the row needs. Click the error, choose Select Obstructing Cells, and clear them.
#NAME? when a colleague opens the fileThe formula shows #NAME? when the file is opened by a colleague.TOROW exists only in Excel 2024, Microsoft 365 and Excel for the web. For older versions use TRANSPOSE on a single column.