Part I. The language · this page as markdown

Working over lists

A guest log holds a list of names; a garden, a list of beds; a week, a list of days. This chapter is about the words that work over a whole list at once, so you rarely need to step through one yourself.

map #

map takes a word and a list, and answers the list of what the word gives for each item:

#lists-map
(map inc [1 2 3])
(map upper ["rose" "sage"])
(map count ["rose" "sage" "lavender"])
It answers
(2 3 4)
("ROSE" "SAGE")
(4 4 8)

The word can be one of the language's, or one you write on the spot with fn (chapter 6 says more):

#lists-map-fn
(map (fn [n] (* n n)) [1 2 3 4])
(map (fn [guest] (str "Hello, " guest ".")) ["Mira" "Cairn"])
It answers
(1 4 9 16)
("Hello, Mira." "Hello, Cairn.")

Given two lists, map takes an item from each in turn:

#lists-map-two
(map (fn [flower n] (str n " " flower)) ["roses" "asters"] [3 5])
It answers
("3 roses" "5 asters")

mapv is map that answers a square-bracket list, which is what to use when you keep the result.

for #

for says the same as map in another order: a name, the list it goes over, and what to make from each:

#lists-for
(for [flower ["rose" "sage" "moss"]]
  (str flower " bed"))
It answers
("rose bed" "sage bed" "moss bed")

A for here goes over one list with one name. To go over two lists together, use map with both, as above.

filter and remove #

filter keeps the items a test holds for; remove keeps the others:

#lists-filter
(filter even? (range 10))
(remove even? (range 10))
(filter (fn [w] (> (count w) 3)) ["oak" "fern" "ash" "willow"])
It answers
(0 2 4 6 8)
(1 3 5 7 9)
("fern" "willow")

keep does a map and a filter at once: it keeps what the word gives, leaving out nil.

#lists-keep
(keep (fn [n] (when (odd? n) (* n 10))) [1 2 3 4 5])
It answers
(10 30 50)

reduce #

reduce folds a list into one value. It takes a word of two values, a value to start from, and the list; it calls the word on the start and the first item, then on that answer and the next item, and so on:

#lists-reduce
(reduce + 0 [1 2 3 4])
(reduce max 0 [3 9 4])
(reduce (fn [total word] (+ total (count word))) 0 ["rose" "sage" "moss"])
It answers
10
9
12

The third adds up the lengths: 0 and "rose" make 4, 4 and "sage" make 8, and 8 and "moss" make 12.

reduce can build a map as easily as a number. This counts how often each flower comes up:

#lists-reduce-map
(reduce (fn [counts flower] (update counts flower (fnil inc 0)))
        {}
        ["rose" "sage" "rose" "moss" "rose"])
It answers
{"rose" 3, "sage" 1, "moss" 1}

(fnil inc 0) is inc that treats a missing value as 0. Counting is common enough to have its own word, frequencies, below.

Asking about a whole list #

#lists-ask
(some even? [1 3 4 5])
(every? pos? [1 2 3])
(not-any? neg? [1 2 3])
(some (fn [g] (when (= g "@mira") "she's been")) ["@cairn" "@mira"])
It answers
true
true
true
"she's been"

some answers the first value the word gives that counts as true, so it can find as well as test.

Sorting and grouping #

#lists-sort
(sort-by count ["willow" "oak" "fern"])
(sort > [3 1 2])
(frequencies ["rose" "sage" "rose"])
(group-by count ["oak" "ash" "fern" "elm"])
(max-key count "oak" "willow" "fern")
It answers
("oak" "fern" "willow")
(3 2 1)
{"rose" 2, "sage" 1}
{3 ["oak" "ash" "elm"], 4 ["fern"]}
"willow"

sort-by sorts by what a word gives for each item. group-by makes a map from what the word gives to the items that gave it.

More list words #

A few more, each a small job done for you:

#lists-more
(map-indexed (fn [i flower] (str (inc i) ". " flower)) ["rose" "sage"])
(take-while (fn [n] (< n 3)) [1 2 3 1])
(partition 2 [1 2 3 4 5 6])
(interpose "and" ["rose" "sage" "moss"])
(mapcat (fn [n] [n n]) [1 2 3])
(apply + [1 2 3])
It answers
("1. rose" "2. sage")
(1 2)
((1 2) (3 4) (5 6))
("rose" "and" "sage" "and" "moss")
(1 1 2 2 3 3)
6

apply calls a word with the items of a list as what it takes: (apply + [1 2 3]) is (+ 1 2 3).

Repeating something a number of times #

At the top of a plan, dotimes runs its forms a number of times, counting from 0. It is the way to do a step more than once, such as adding to an atom (chapter 2) or changing the house (chapter 15). Its count is at most 100:

#lists-dotimes
(let [stars (atom [])]
  (dotimes [i 5]
    (swap! stars conj "*"))
  (join "" (deref stars)))
It answers
"*****"

swap! at the top of a plan takes the shapes chapter 2 listed (+, -, not, conj, assoc, update); work anything else out with the words of this chapter, as join does here.

Try it #

  1. Answer the squares of 1 to 10, as a square-bracket list.
  2. From ["@mira" "@cairn" "@mira" "@wisp" "@mira"], answer who came most, with frequencies and max-key, or another way.
  3. With reduce, answer the longest word in ["oak" "willow" "fern"].
  4. With filter, answer the names in a list that start with "@m".

Recap #

Next: writing words of your own.

Written by Claude, Plazmi's writer, for Plazmi, a service of Manatee Media LLC. Text © 2026 Manatee Media LLC. The examples are free to copy, change and run.