Core Concepts

Iterators

Each, each-both, each-left, each-right, scan, over — higher-order iteration in q.

Overview

Iterators (', /, \, \:, /:, ':) are the idiomatic way to apply functions across lists and dictionaries in q. An iterator takes a function and returns a new, derived function that applies the original in a particular pattern.

A note on names: iterators are sometimes called adverbs in older q/k documentation and community discussion — likewise verb maps to operator/keyword, and valence maps to rank. The Terminology page uses the modern names throughout; it's worth recognising "adverb", "verb", and "valence" as the same concepts if you encounter them elsewhere.

Maps vs Accumulators

Iterators fall into two groups:

  • Maps distribute the application of a function across the items of a list or dictionary, and are implicitly parallel. This group includes Each ('), Each Prior, Each Parallel (peach), Each Left (\:), Each Right (/:), and Case — some of these share glyphs (e.g. ': is both Each Prior and Each Parallel, depending on context).
  • Accumulators — Over (/) and Scan (\) — apply a function successively: first to the whole argument, then to the result of that, and so on. With a binary function, these correspond to map-reduce and fold in other languages.

This page covers Each-Both, Converge, and Over and Scan with a seed. The practice sections cover Each, Each Left, Each Right, Over, Scan and amend.

Each-Both

Each-both (') applied to a binary function applies that function to corresponding pairs of items from two lists. For atomic functions like +, this looks identical to plain application:

+'[1 2;10 20]    / 11 22  (same as 1 2 + 10 20)

Each-both is more meaningful for functions that aren't atomic. The join operator , normally concatenates two lists end to end — but with ,', it joins them pairwise, item by item:

(1 2;3 4),(10 20;30 40)    / plain join  -> (1 2;3 4;10 20;30 40)   four rows
(1 2;3 4),'(10 20;30 40)   / each-both   -> (1 2 10 20;3 4 30 40)   two rows

Converge

Converge is a special form of the Over (/) and Scan (\) iterators: when no iteration count or stopping condition is given, the function is applied repeatedly until the result stops changing.

raze removes one level of nesting from a list:

nested: (1;(2;(3;4));5)
raze nested
/ 1
/ 2
/ 3 4
/ 5

Using Converge (raze/), raze is applied repeatedly until the result is fully flat:

raze/[nested]
/ 1 2 3 4 5

Converge is uncommon in mainstream languages but is a powerful tool in q, especially for recursive or arbitrarily nested data structures.

Do and While are two close relatives — they use the same Over/Scan syntax but control when to stop differently:

  • Do (n f/ x) — apply f exactly n times. Use Scan (\) to see every intermediate step, or Over (/) for the final result only:
3 {x+1}\ 5    / 5 6 7 8   (start, then 3 steps)
3 {x+1}/ 5    / 8          (final result only)
  • While (t f/ x) — keep applying f until the test function t returns false. Again, \ for all steps, / for just the end:
{x<100} {x*2}\ 1    / 1 2 4 8 16 32 64 128
{x<100} {x*2}/ 1    / 128

Converge applies to any unary function, not just raze. A classic example is summing a matrix — expressions like these are shorter and usually faster than an explicit loop:

m: (1 2 3;4 5 6;7 8 9)

+/[m]    / sum the columns -> 12 15 18
+/'[m]   / sum each row    -> 6 15 24
+//[m]   / sum everything  -> 45   (Converge: +/ applied repeatedly until the result stops changing)

Seeded Over & Scan

Both Over (/) and Scan (\) accept an optional seed (initial value) as a left argument — this is the binary form of the derived function:

+\[1 2 3]        / unary  -> 1 3 6   (running totals)
+\[1; 1 2 3]     / binary -> 2 4 7   (seed 1, then running totals)
1 +\ 1 2 3       / same as above, written infix -> 2 4 7

The same applies to / (e.g. +/[100;1 2 3 4] → 110). See the Terminology page's "Derived Function" section for a syntax gotcha around writing these forms without brackets or parentheses.