Skip to content

List

Built-in type · Written [90, 72, 85], or [] for an empty list

A List holds items of one type, in order: the scores in a game, the lines of a file, the names in a class. Its type is written with the type of its items, such as List[Int] or List[String]. On this page, T stands for that item type.

var scores = [90, 72, 85]
scores.append(100)
print(scores[0]) # prints 90
print(scores.count) # prints 4
for score in scores {
print(score)
}

An empty list needs its type written out, since there is nothing in it to go by: var names: List[String] = [].

Positions count from 0, so scores[0] is the first item and scores[scores.count - 1] the last. A position outside the list raises an error rather than giving a wrong answer.

A list is a value. Assigning a list to another variable gives that variable its own copy, so changing one never changes the other:

var mine = [1, 2, 3]
var yours = mine
yours.append(4)
print(mine.count, yours.count) # prints 3 4

Only a var list can change. Methods that change a list are marked on this page: the ones that add and remove items, and every method whose name ends in !. Such a method changes the list and gives back nothing, so scores.sort!() sorts scores itself, while scores.sort() leaves it alone and gives back a sorted copy. The same pairs exist for reverse, unique, and shuffle.

Many methods take a block, written in braces after the call, which runs for each item: scores.filter { score => score > 80 }.

Size and ends
count How many items it has
empty?() Whether it has none
first, last The first or last item
Adding and removing (changes the list)
append(item), insert(index, item) Add an item
remove(item), remove_all(item), remove_if { ... } Remove items by value
remove_at(index), remove_first(), remove_last() Remove an item by position
clear() Remove every item
Searching
contains?(item) Whether an item is in it
find { ... }, find_index { ... } The first item a block accepts, or its position
Visiting each item
each { ... }, each_with_index { ... }, reverse_each { ... } Run a block for each item
Making new lists
map { ... } Each item changed by a block
filter { ... }, reject { ... } The items a block accepts, or rejects
flat_map { ... }, filter_map { ... } Several items, or none, for each item
take(count), drop(count) The first items, or all but the first
take_while { ... }, drop_while { ... } Items from the start, while a block accepts them
Ordering
sort(), sort_by { ... }, sort!() Smallest first
reverse(), reverse!() Last first
shuffle(), shuffle!(), random() In a random order, or one item at random
Duplicates
unique(), unique!(), unique_by { ... } Each item once
Questions about the items
any? { ... }, all? { ... }, none? { ... }, one? { ... } Whether a block accepts some, all, none, or exactly one
count_where { ... } How many a block accepts
Numbers
sum(), average() Add them up, or find the mean
min(), max(), min_max() The smallest and largest
min_by { ... }, max_by { ... } The item with the smallest or largest key
Combining and splitting
chain(other), zip(other) Join two lists, or pair them up
chunks(size), windows(size), pairs() Pieces of a list
partition { ... } Split in two by a block
Reducing
reduce(initial) { ... }, reduce_right(initial) { ... } Combine every item into one value
Converting
to_set(), to_dictionary() A Set or Dict of the items
frequencies(), group_by { ... } Count or group the items
associate { ... }, associate_by { ... } A Dict built by a block
Operator Meaning Example
list[index] The item at a position [5, 3, 8][1] → 3
list[index] = item Change the item at a position scores[0] = 95
list[start..<end] Part of the list [5, 3, 8, 1][1..<3] → [3, 8]
== != Compare [1, 2] == [1, 2] → true

list[start..<end] stops before end, and list[start..end] includes it; either end can be left out inside the brackets, as in scores[..<2]. The part is a new list of its own.

Two lists are equal when they hold equal items in the same order. There is no + for lists; join two with chain.

A list prints the way it is written: [90, 72, 85].

count: Int

How many items the list has.

[90, 72, 85].count # → 3

empty?(): Bool

Whether the list has no items.

[90, 72, 85].empty?() # → false

first: T?

The first item, or nothing when the list is empty.

[90, 72, 85].first # → 90

A list can hold nothing itself, as a List[String?] can, so to tell an empty list apart from one whose first item is nothing, check empty?().

last: T?

The last item, or nothing when the list is empty.

[90, 72, 85].last # → 85

These change the list, so they need a var list.

append(item: T)

Adds item at the end.

var scores = [90, 72]
scores.append(85)
print(scores) # prints [90, 72, 85]

insert(index: Int, item: T)

Adds item at position index, moving the items after it along. An index equal to count adds it at the end.

var letters = ["a", "b", "c"]
letters.insert(1, "x")
print(letters) # prints ["a", "x", "b", "c"]

Raises when index is negative or greater than count.

remove(item: T)

Removes the first item equal to item. When there is none, nothing happens.

var letters = ["a", "x", "b"]
letters.remove("x")
print(letters) # prints ["a", "b"]

remove_all(item: T)

Removes every item equal to item.

var numbers = [1, 2, 1, 3, 1]
numbers.remove_all(1)
print(numbers) # prints [2, 3]

remove_if { item: T => Bool }

Removes every item the block accepts. To get a new list instead, use reject.

var numbers = [1, 2, 3, 4, 5, 6]
numbers.remove_if { n => n.odd?() }
print(numbers) # prints [2, 4, 6]

remove_at(index: Int): T

Removes the item at position index and gives it back.

var queue = ["a", "b", "c"]
print(queue.remove_at(1)) # prints b
print(queue) # prints ["a", "c"]

Raises when there is no item at index.

remove_first(): T

Removes the first item and gives it back.

var queue = ["a", "b", "c"]
print(queue.remove_first()) # prints a

Raises when the list is empty.

remove_last(): T

Removes the last item and gives it back.

var stack = ["a", "b", "c"]
print(stack.remove_last()) # prints c

Raises when the list is empty.

clear()

Removes every item.

var scores = [90, 72]
scores.clear()
print(scores) # prints []

contains?(item: T): Bool

Whether an item equal to item is in the list.

[1, 2, 3].contains?(2) # → true

find { item: T => Bool }: T?

The first item the block accepts, or nothing when it accepts none.

[4, 7, 10].find { n => n > 5 } # → 7
[4, 7].find { n => n > 50 } # → nothing

find_index { item: T => Bool }: Int?

The position of the first item the block accepts, or nothing when it accepts none.

[4, 7, 10].find_index { n => n > 5 } # → 1

each { item: T => ... }

Runs the block once for each item, in order. It is the same as a for loop.

["Ada", "Grace"].each { name => print("Hello, #{name}") }
# prints Hello, Ada, then Hello, Grace

each_with_index { item: T, index: Int => ... }

Runs the block for each item, with its position.

["Ada", "Grace"].each_with_index { name, index => print("#{index}: #{name}") }
# prints 0: Ada, then 1: Grace

reverse_each { item: T => ... }

Runs the block for each item, from last to first.

[1, 2, 3].reverse_each { n => print(n) }
# prints 3, 2, 1

These leave the list as it was and give back a new one.

map { item: T => U }: List[U]

Each item, changed by the block.

[1, 2, 3].map { n => n * 10 } # → [10, 20, 30]

filter { item: T => Bool }: List[T]

The items the block accepts, in order.

[1, 2, 3, 4].filter { n => n.even?() } # → [2, 4]

reject { item: T => Bool }: List[T]

The items the block does not accept.

[1, 2, 3, 4].reject { n => n.even?() } # → [1, 3]

flat_map { item: T => List[U] }: List[U]

The items of every list the block gives, joined into one list.

[1, 2].flat_map { n => [n, n] } # → [1, 1, 2, 2]

filter_map { item: T => U? }: List[U]

What the block gives for each item, leaving out every nothing.

["1", "x", "3"].filter_map { text => text.to_int_maybe() } # → [1, 3]

take(count: Int): List[T]

The first count items. When the list is shorter, all of it.

[1, 2, 3, 4].take(2) # → [1, 2]
[1, 2].take(5) # → [1, 2]

Raises when count is negative.

drop(count: Int): List[T]

Everything after the first count items.

[1, 2, 3, 4].drop(2) # → [3, 4]

Raises when count is negative.

take_while { item: T => Bool }: List[T]

Items from the start, up to the first one the block does not accept.

[1, 2, 5, 1].take_while { n => n < 3 } # → [1, 2]

drop_while { item: T => Bool }: List[T]

Everything from the first item the block does not accept.

[1, 2, 5, 1].drop_while { n => n < 3 } # → [5, 1]

sort(): List[T]

The items from smallest to largest. Numbers, text, and structs that adopt Ordered can be sorted. Equal items keep their order.

[3, 1, 2].sort() # → [1, 2, 3]

Raises when a Float in the list is not a number (Float.nan).

sort_by { item: T => K }: List[T]

The items, ordered by the key the block gives for each, smallest first.

["pear", "fig", "banana"].sort_by { word => word.count } # → ["fig", "pear", "banana"]

sort!()

Sorts the list itself, smallest first.

var order = [3, 1, 2]
order.sort!()
print(order) # prints [1, 2, 3]

reverse(): List[T]

The items in the opposite order.

[1, 2, 3].reverse() # → [3, 2, 1]

reverse!()

Reverses the list itself.

shuffle(): List[T]

The items in a random order.

shuffle!()

Puts the list itself in a random order.

random(): T?

One item, chosen at random, or nothing when the list is empty.

print(["rock", "paper", "scissors"].random()) # prints one of the three

unique(): List[T]

Each item once, keeping the first of each.

[1, 2, 1, 3].unique() # → [1, 2, 3]

unique!()

Removes repeated items from the list itself, keeping the first of each.

unique_by { item: T => K }: List[T]

The first item for each key the block gives.

["apple", "avocado", "banana"].unique_by { word => word[0] } # → ["apple", "banana"]

any? { item: T => Bool }: Bool

Whether the block accepts at least one item. An empty list gives false.

[1, 5].any? { n => n > 4 } # → true

all? { item: T => Bool }: Bool

Whether the block accepts every item. An empty list gives true.

[1, 5].all? { n => n > 4 } # → false

none? { item: T => Bool }: Bool

Whether the block accepts no item. An empty list gives true.

[1, 5].none? { n => n > 9 } # → true

one? { item: T => Bool }: Bool

Whether the block accepts exactly one item.

[1, 5].one? { n => n > 4 } # → true

count_where { item: T => Bool }: Int

How many items the block accepts.

[1, 5, 8].count_where { n => n > 4 } # → 2

These need a list of numbers, or for min and max, of anything that can be ordered.

sum(): T

All the items added up. An empty list sums to 0.

[1, 2, 3, 4].sum() # → 10

Raises when the total is too large for an Int.

average(): Float?

The mean of the items, or nothing when the list is empty.

[1, 2].average() # → 1.5

min(): T?

The smallest item, or nothing when the list is empty.

[3, 1, 2].min() # → 1

max(): T?

The largest item, or nothing when the list is empty.

[3, 1, 2].max() # → 3

min_max(): (T?, T?)

The smallest and largest items together, found in one pass.

[3, 1, 2].min_max() # → (1, 3)

min_by { item: T => K }: T?

The item whose key, from the block, is smallest.

["pear", "fig"].min_by { word => word.count } # → "fig"

max_by { item: T => K }: T?

The item whose key, from the block, is largest.

["pear", "fig"].max_by { word => word.count } # → "pear"

chain(other: List[T]): List[T]

This list’s items followed by other’s.

[1, 2].chain([3, 4]) # → [1, 2, 3, 4]

zip(other: List[U]): List[(T, U)]

Items paired by position with other’s. When one list is longer, its extra items are left out.

[1, 2, 3].zip(["a", "b"]) # → [(1, "a"), (2, "b")]

chunks(size: Int): List[List[T]]

The items in pieces of size, in order. The last piece may be smaller.

[1, 2, 3, 4, 5].chunks(2) # → [[1, 2], [3, 4], [5]]

Raises when size is less than 1.

windows(size: Int): List[List[T]]

Every run of size items side by side, one step apart.

[1, 2, 3, 4].windows(2) # → [[1, 2], [2, 3], [3, 4]]

Raises when size is less than 1.

pairs(): List[(T, T)]

Each item paired with the one after it.

[1, 2, 3].pairs() # → [(1, 2), (2, 3)]

partition { item: T => Bool }: (List[T], List[T])

The items the block accepts, and the ones it does not.

[1, 2, 3, 4, 5].partition { n => n > 2 } # → ([3, 4, 5], [1, 2])

reduce(initial: A) { total: A, item: T => A }: A

Combines the items into one value. The block gets the total so far, starting at initial, and the next item, and gives the new total. An empty list gives initial.

[1, 2, 3].reduce(0) { total, n => total + n } # → 6

reduce_right(initial: A) { total: A, item: T => A }: A

The same as reduce, from the last item to the first.

["a", "b", "c"].reduce_right("") { text, letter => text + letter } # → "cba"

to_set(): Set[T]

A Set of the items, each once.

[3, 1, 3].to_set() # → {3, 1}

to_dictionary(): Dict[K, V]

A Dict from a list of (key, value) pairs. A later pair with the same key replaces the earlier value.

[("Ada", 36), ("Grace", 45)].to_dictionary() # → ["Ada": 36, "Grace": 45]

frequencies(): Dict[T, Int]

How many times each item appears.

["a", "b", "a"].frequencies() # → ["a": 2, "b": 1]

group_by { item: T => K }: Dict[K, List[T]]

The items grouped by the key the block gives for each.

["apple", "avocado", "banana"].group_by { word => word[0] } # → ["a": ["apple", "avocado"], "b": ["banana"]]

associate { item: T => (K, V) }: Dict[K, V]

A Dict with the key and value the block gives for each item.

["Ada", "Grace"].associate { name => (name, name.count) } # → ["Ada": 3, "Grace": 5]

associate_by { item: T => K }: Dict[K, T]

A Dict from the key the block gives to each item itself.

["Ada", "Grace"].associate_by { name => name[0] } # → ["A": "Ada", "G": "Grace"]

A block that a list method calls, such as the one given to remove_if, sort_by, min_by, unique_by, or group_by, may read the list the method is working on. It may not change it. The block sees the list as it was when the method started, never a half-sorted or half-trimmed one, and the method puts its finished result in place only after every call has succeeded. If a block raises an error, the list is left as it was.

var numbers = [1, 2, 3, 4, 5]
numbers.remove_if { n => n > numbers.count - 2 }
print(numbers)
Output
[1, 2, 3]

The block reads numbers.count, which is 5 for every item, since it sees the original. Changing the list from inside the block is refused with an error you can catch, which names the list and the method:

var numbers = [1, 2, 3, 4]
numbers.remove_if { n =>
numbers.append(9)
return n > 2
}
Output
lists.em:3:5: a callback cannot change `numbers` while `remove_if` is using it
numbers.append(9)
^^^^^^^
A callback cannot change the list it is being called for; copy it first, or collect the changes and apply them after.
in a block, called at lists.em:2:1

A separate copy of the list is a different value and may be changed freely. Otherwise, collect what you want to change and apply it after the method finishes. Ordinary visiting methods such as each and reduce work on a snapshot already, and may change the list they started from.