#Collections
Status: standard library specification draft.
This chapter defines the part of std.collections that lib/std writes
in ordinary hd over the language tier:
- the
Listmethodsviewandchunks, and the access and building methods such asget,take, andextend; - the
ListView[T]type returned byview,chunks, andwindows; - the
Listhelpers, such assorted_by_key,group_by, andwindows, and the functioncounts; - the
Mapmethodscontains_key,keys,values, andget_or; - the set
Set[T], the double-ended queueDeque[T], and the max-heapHeap[T], which are values as a list is.
The language tier keeps what the compiler knows about a list (List Indexing, Built-In Methods, Iterator Snapshots):
| Item | Why it stays in the language tier |
|---|---|
items[i], len, iter, push, pop, insert, remove_at, clear |
built-in indexing and intrinsics over the list's representation |
#List And Map Values
A list or a map is a value (Collection Values),
and the std methods treat it as one.
fn joined(first: List[i32], second: List[i32]) -> List[i32]:
let mut all = first
all.extend(second) # first is unchanged
all- std-collections.value.receiverA
stdmethod that changes a list or a map, asextenddoes, needs its receiver in a writable place, as a language-tier changing method does (types.coll.writable). - std-collections.value.own-copySuch a change reaches only the receiver's own value. Another copy of the list or the map is unchanged.
- std-collections.value.resultsA method that returns a list or a map, as
keys,filter, andchunksdo, returns a new value, which the caller may bind withlet mutand change. - std-collections.value.pinned-lengthA
stdmethod that changes the length of a pinned list or map, asextendwith a non-empty list does, is a checked runtime panic, as a language-tier change is (ref.elem.pinned,ref.elem.pinned.map). Panic:collection-pinned. - std-collections.value.ref-receiverEach such method takes
&mut self. On a map value or a list element, as ingroups[key].extend(more), it changes the collection where it is stored, astypes.coll.nestedstates for every change through a path.
#List Methods
std gives List[T] these methods, beside the language-tier ones:
| Receiver | Methods |
|---|---|
List[T] |
view(*self, start: usize, end: usize) -> ListView[T]; chunks(*self, size: usize) -> List[ListView[T]] |
- std-collections.list.chunks.views
chunks(size)returns consecutive read-onlyListView[T]values in order; only the last view may be shorter thansize. - std-collections.list.chunks.sizeA
sizebelow 1 panics. Panic:explicit-panic. - std-collections.list.window-borrow
chunksandwindowstake&self, so every returned view refers to the receiver's place. - std-collections.list.window-costBoth methods create one result list of views and should copy no elements.
use std.collections.ListView
fn pairs(items: *List[i32]) -> List[ListView[i32]]:
items.chunks(2) # views of [1, 2] and [3] for [1, 2, 3]Note.
piece.to_list()copies a returned view into a list. A copy of a run of elements is also a slice,items[start..end], a new list (Slicing).
#Views
view gives a read-only window on a run of a list's elements, with no
copy. It refers to the list's place, as a &self method does:
use std.collections.ListView
fn window(items: List[i32]) -> ListView[i32]:
items.view(1, 3)
fn total(view: ListView[i32]) -> i32:
let sum = 0
for item in view:
sum = sum + item
sum + view[view.len() - 1]ListView[T] has this surface:
| Item | Signature |
|---|---|
len |
len(self) -> usize |
to_list |
to_list(self) -> List[T] |
| index read | Index[usize] with Out = T |
| iteration | Iterable[T] |
- std-collections.view
view(start, end)returns aListView[T]of the list's elements at indicesstartup to, not including,end. - std-collections.view.type
std.collectionsdeclaresListView[T]with private fields and the surface in the table above, and no other method or trait implementation. - std-collections.view.place
viewtakes&self, so the view refers to the list's place: a binding, a field, or a value reached through a reference. Called on a list that is no place, such as a call result, it refers to a new object that holds the list. - std-collections.view.valueA
ListView[T]is a struct value. A copy of a view is another window on the same place. - std-collections.view.import
ListViewis not a prelude name, so code that names it imports it, as inuse std.collections.ListView. - std-collections.view.no-copyCreating a view copies no element.
- std-collections.view.rangeA
startorendthat is greater than the list's length is a checked runtime panic. Panic:index-out-of-bounds. - std-collections.view.reversedA
startgreater thanendis a checked runtime panic. Panic:index-out-of-bounds. - std-collections.view.len
lenreturns the number of elements in the view,end - start. - std-collections.view.index
view[i]reads the list's element at indexstart + i. - std-collections.view.index.rangeA view index that is not less than the view's
lenis a checked runtime panic, even when the list has an element there. Panic:index-out-of-bounds. - std-collections.view.iterIterating a view yields its elements in order, each as
T. - std-collections.view.cursorA view's cursor type is
ListViewIter[T], whichstd.collectionsdeclares with private fields. - std-collections.view.to-list-value
to_listreturns a new list value that holds the view's elements in order, as the sliceitems[start..end]does, solet mut copy = view.to_list()may grow the copy. - std-collections.view.read-onlyA view has no
IndexSetimplementation, so assigning toview[i]is an error. Error:invalid-assignment-target. - std-collections.view.writesAn element write to the list's place, as
items[i] = v, shows through every view of it, so a later read of the view gives the new value. - std-collections.view.invalidateChanging the list's length invalidates every view of it.
- std-collections.view.invalidate.anywhereA length change invalidates a view wherever it happens, so appending past a view's end invalidates it too.
- std-collections.view.invalid-useThe next use of an invalidated view is a checked runtime panic. Such a use is a
len, index, orto_listcall, aniter()call, or the nextnextcall of an iterator taken from it. Panic:iterator-invalidated.
use std.collections.ListView
fn invalid(mut view: ListView[i32]) -> void:
view[0] = 7 # error: invalid-assignment-targetfn stale(items: *mut List[i32]) -> usize:
window := items.view(0, 2)
items.push(4)
window.len() # panics with iterator-invalidatedWhy. A view fails fast, as Java's
subListdoes: a window whose list changed length would otherwise read the wrong elements without notice.
See also: List Indexing, List And Optional Map.
#List Helpers
std also gives List[T] helpers that sort, group, split, and search a
list without a hand-written loop:
use std.collections.ListView
struct Task:
name: string
owner: string
hours: i32
fn plan(tasks: List[Task]) -> List[Task]:
tasks.sorted_by_key(fn(task: Task) -> i32: task.hours)
fn by_owner(tasks: List[Task]) -> Map[string, List[Task]]:
tasks.group_by(fn(task: Task) -> string: task.owner)
fn has_long(tasks: List[Task]) -> bool:
tasks.any(fn(task: Task) -> bool: task.hours > 8)
fn steps(readings: *List[i32]) -> List[ListView[i32]]:
readings.windows(2) # views of [1, 4] and [4, 9] for [1, 4, 9]
fn shortest(tasks: List[Task]) -> Task?:
tasks.min_by_key(fn(task: Task) -> i32: task.hours) # the first of equal hours
fn owners(tasks: List[Task]) -> List[string]:
tasks.map(fn(task: Task) -> string: task.owner).unique() # ["bo", "al"] for bo, al, bo| Receiver | Methods |
|---|---|
List[T] |
sorted_by_key[K < Ord](self, key: fn(T) -> K) -> List[T]; group_by[K < Eq & Hash](self, key: fn(T) -> K) -> Map[K, List[T]]; partition(self, keep: fn(T) -> bool) -> (List[T], List[T]); any(self, test: fn(T) -> bool) -> bool; all(self, test: fn(T) -> bool) -> bool; find(self, test: fn(T) -> bool) -> T?; flat_map[U, I < Iterable[U]](self, transform: fn(T) -> I) -> List[U]; windows(*self, size: usize) -> List[ListView[T]] |
List[T] |
min_by_key[K < Ord](self, key: fn(T) -> K) -> T?; max_by_key[K < Ord](self, key: fn(T) -> K) -> T? |
List[T], when T < Eq |
contains(self, value: T) -> bool; index_of(self, value: T) -> usize?; dedup(self) -> List[T] |
List[T], when T < Eq & Hash |
unique(self) -> List[T] |
List[T], when T < Ord |
sorted(self) -> List[T]; min(self) -> T?; max(self) -> T? |
List[T], when T < Num |
sum(self) -> T |
- std-collections.helper.unchangedEach helper leaves its receiver unchanged, and each one that returns a list returns a new list.
- std-collections.helper.callback-orderA helper calls its callback on the elements in list order, at most once each.
- std-collections.helper.callback-rowEach callback has the empty row, as
Iterator.filter'skeepdoes. A function value whose row lists a requirement key does not fit it. Error:type-mismatch. - std-collections.helper.sorted-by-key
sorted_by_key(key)returns the elements in ascending order ofkey(element)byOrd, and callskeyonce per element. - std-collections.helper.sorted
sortedreturns the elements in ascending order byOrd. - std-collections.helper.stableBoth sorts are stable: elements that compare equal keep their order.
- std-collections.helper.group-by
group_by(key)maps each key thatkeyreturns to the list of the elements that gave it, in list order. - std-collections.helper.partition
partition(keep)returns the elements for whichkeepis true, then the rest, each in list order. - std-collections.helper.any-all
any(test)is true whentestis true for some element, andall(test)when it is true for every element. So on an empty listanyis false andallis true. - std-collections.helper.find
find(test)returns the first element for whichtestis true in.Some, or.Nonewhen there is none. - std-collections.helper.short-circuit
any,all, andfindcallteston no element after the first one that decides the result. - std-collections.helper.flat-map.iterable-owned
flat_map(transform)appends every item from each returnedIterableinto one result list, in source order. - std-collections.helper.windows.views
windows(size)returns overlappingListView[T]values ofsizeelements, in starting-index order. - std-collections.helper.windows.shortA list with fewer than
sizeelements gives[]. - std-collections.helper.windows.sizeA
sizebelow 1 panics, as it does forchunks. Panic:explicit-panic. - std-collections.helper.contains
contains(value)is true when an element equalsvaluebyEq.index_of(value)returns the index of the first such element in.Some, or.None. - std-collections.helper.min-max.first
minreturns the first smallest element andmaxthe first largest one byOrd, each in.Some. An empty list gives.None. - std-collections.helper.sum
sumreturns the total of the elements, added with+in list order from 0 of typeT, so an empty list gives 0. - std-collections.helper.sum.overflowAn integer total that leaves the range of
Tpanics, as+does. Panic:integer-overflow. - std-collections.helper.sum.iterator
items.sum()returns whatitems.iter().sum()returns. - std-collections.helper.by-key.first
min_by_key(key)returns the first element whosekeyis smallest byOrd, andmax_by_key(key)the first whosekeyis largest, each in.Some, so equal keys give the earlier element, asminandmaxdo. An empty list gives.None. - std-collections.helper.dedup
dedupreturns the list without each element that equals the element just before it in the receiver, as Rust'sVec::dedupdoes, so only adjacent duplicates go and[1, 2, 1]is unchanged. - std-collections.helper.unique
uniquereturns the list without each element that equals an earlier element, so every distinct element stays once, at its first position.
| Call | Result |
|---|---|
[3, 1, 2].partition(fn(n: i32) -> bool: n > 1) |
([3, 2], [1]) |
[1, 2].flat_map(fn(n: i32) -> List[i32]: [n, n]) |
[1, 1, 2, 2] |
[1, 2, 3].windows(2) |
views of [1, 2] and [2, 3] |
[1, 2].windows(3) |
[] |
[5, 7, 5].index_of(5) |
.Some(0) |
[2, 9, 4].max() |
.Some(9) |
["bb", "a", "cc"].max_by_key(fn(w: string) -> usize: w.len()) |
.Some("bb") |
[1, 1, 2, 1].dedup() |
[1, 2, 1] |
[1, 1, 2, 1].unique() |
[1, 2] |
[1, 2, 3].sum() |
6 |
[0.5, 0.25].sum() |
0.75 |
[] of i64, .sum() |
0 |
fn paged(items: List[i32]) -> List[List[i32]]:
items.windows(0) # panics with explicit-panicWhy. The names are Rust's (
sort_by_key,partition,windows,any,all,find,flat_map,contains,min,max), Kotlin'sgroupBy, and Python'slist.index. A sort copies, assorted_bydoes, since hd has no consuming methods.minandmaxboth pick the first of equal elements, as Python'sminandmaxdo, so one rule covers both.sumis Python'ssumand Rust'sIterator::sum; a list has it as a method besideminandmax, since a list is not an iterator.
dedupisVec::dedup, which removes every duplicate only from a sorted list;uniqueis what Python'sdict.fromkeysgives for a list that is not sorted. The names differ because the results differ.
#Counts
counts tallies how often each element occurs:
use std.collections.counts
fn tally(words: List[string]) -> Map[string, usize]:
counts(words) # {"a": 2, "b": 1} for ["a", "b", "a"]- std-collections.counts.decl
std.collectionsdeclarespub fn counts[T < Eq & Hash](items: List[T]) -> Map[T, usize]. Code imports it, as inuse std.collections.counts. - std-collections.counts.valueThe map has one entry per distinct element of
items, and its value is the number of elements equal to that one. - std-collections.counts.emptyAn empty list gives an empty map.
Why.
countsis Python'scollections.Counteras a plain map, so theMapmethods read it.
#Map Methods
std gives Map[K, V] these methods, beside the language-tier ones:
| Receiver | Methods |
|---|---|
Map[K, V] |
contains_key(self, key: K) -> bool; keys(self) -> List[K]; values(self) -> List[V]; is_empty(self) -> bool; entries(self) -> List[(K, V)] |
Map[K, usize] |
most_common(self, n: usize) -> List[(K, usize)] |
fn summary(stock: Map[string, i32]) -> string:
if stock.contains_key("tea"):
return "${stock.keys().len()} items"
"no tea"
fn top_words(words: List[string]) -> List[(string, usize)]:
counts(words).most_common(2) # [("a", 2), ("b", 1)] for ["a", "b", "a", "c"]
fn pairs(stock: Map[string, i32]) -> List[(string, i32)]:
stock.entries() # [("tea", 3), ("milk", 1)] for {"tea": 3, "milk": 1}- std-collections.map.contains-key
contains_key(key)is true exactly when the map has an entry whose key equalskey. - std-collections.map.keys.order
keysreturns the map's keys in its iteration order. - std-collections.map.values
valuesreturns the map's values in the same order. - std-collections.map.snapshotEach returned list is a snapshot: a later change to the map does not change it.
- std-collections.map.is-empty
is_emptyis true exactly whenlen()is 0. - std-collections.map.entries
entriesreturns the map's(key, value)pairs in its iteration order, which is the order ofkeysandvalues, as a snapshot like theirs. - std-collections.map.most-common
most_common(n)returns thenpairs of the map with the largest values, largest first, or every pair whennis at leastlen(). Annof 0 gives[]. - std-collections.map.most-common.tiesPairs with equal values keep the map's iteration order, so on a
countsresult the element that occurred first comes first, as in Python'sCounter.most_common.
Why.
entriesis a list snapshot likekeysandvalues, since a loop that sorts or indexes the pairs needs a list.most_commonis Python'sCounter.most_common; a stable sort over the map's order gives its tie rule with no extra bookkeeping.
See also: Map Key Types.
#Set, Deque, And Heap Values
Set[T], Deque[T], and Heap[T] are structs over a list or a map, so
each one is a value, as a list is:
use std.collections.Deque
fn with_last(queue: Deque[string]) -> Deque[string]:
let mut own = queue
own.push_back("last") # the caller's deque is unchanged
own
fn enqueue(queue: &mut Deque[string], name: string) -> void:
queue.push_back(name) # changes the caller's deque- std-collections.struct.value
Set[T],Deque[T], andHeap[T]are structs, so each is a value. Binding, assigning, passing, returning, and storing one copies it, and a change to one copy leaves every other copy unchanged. - std-collections.struct.costA copy shares its source's elements until one of the two changes, as a list does (
types.coll.copy-on-write). - std-collections.struct.receiver-mutMethods that change a collection, such as
push_back,insert, andpop, take&mut self. - std-collections.struct.sharedA set, deque, or heap that two holders share is written
&mut Set[T],&mut Deque[T], or&mut Heap[T]. A change through the reference changes the place it refers to.
Why. These types were shared objects. As values they follow the list they wrap: a copy is cheap until it changes, and sharing is written where it happens.
See also: Reference Receivers
for temporary calls and not-writable on read-only places.
#Set
A Set[T] holds distinct elements, in a deterministic order:
use std.collections.Set
fn unique(words: List[string]) -> List[string]:
let mut seen: Set[string] = Set::new()
let mut kept: List[string] = []
for word in words:
if seen.insert(word):
kept.push(word)
kept # ["b", "a"] for ["b", "a", "b"]
fn distinct(words: List[string]) -> Set[string]:
words.iter().collect()Set[T < Eq & Hash] has this surface:
| Item | Signature |
|---|---|
new |
Set::new() -> Set[T] |
len, is_empty |
len(self) -> usize; is_empty(self) -> bool |
contains |
contains(self, value: T) -> bool |
insert, remove |
insert(&mut self, value: T) -> bool, and the same for remove |
| iteration | Iterable[T] |
collect |
FromIterator[T] |
| equality | Eq |
Debug |
when T < Debug |
- std-collections.set.decl
std.collectionsdeclaresSet[T < Eq & Hash]with private fields, the surface in the table above, and no other method or trait implementation. Code imports it, as inuse std.collections.Set. - std-collections.set.distinctA set holds elements no two of which are equal by
Eq.newreturns an empty set. - std-collections.set.len
lenreturns the number of elements, andis_emptyis true exactly when that number is 0. - std-collections.set.contains
contains(value)is true exactly when the set has an element equal tovalue. - std-collections.set.insert
insert(value)addsvalueand returnstruewhen the set has no element equal to it. Otherwise it changes nothing and returnsfalse. - std-collections.set.remove
remove(value)removes the element equal tovalueand returnstrue. When there is none, it changes nothing and returnsfalse. - std-collections.set.iterIterating a set yields its elements in the order that a map's keys would have after the same inserts and removes, by
types.map.order.deterministic. - std-collections.set.cursorA set's cursor type is
SetIter[T], whichstd.collectionsdeclares with private fields. - std-collections.set.snapshotIterating a set walks the set as it was when
iterwas called. Aninsertor aremovewhile the loop runs changes the set but not the loop, and never panics, asflow.for.snapshotstates for a map. - std-collections.set.eqTwo sets are equal when each element of one equals an element of the other, in any order.
- std-collections.set.collectA set implements
FromIterator[T]. Collecting inserts each item in order, so the set holds each distinct item once, in the order of its first occurrence, and an empty iterator gives an empty set.
Note.
lib/stdbuilds a set over aMapwhose values carry no meaning, soinsert,remove, andcontainstake expected constant time, bymodule.map.complexity.
Why.
insertandremovereport whether they changed the set, as Rust'sHashSetmethods do, so a loop that skips duplicates needs no second lookup. A set iterates in a map's deterministic order, so its iteration andDebugtext are the same in every run. A set is a value, so a loop walks a snapshot of it, as a loop over a map does.
#Deque
A Deque[T] is a double-ended queue: a sequence that grows and shrinks
at both ends.
use std.collections.Deque
fn rotate(items: List[i32]) -> List[i32]:
let mut queue: Deque[i32] = Deque::new()
for item in items:
queue.push_back(item)
match queue.pop_front():
.Some(first) => queue.push_back(first)
.None => pass
let mut rotated: List[i32] = []
for item in queue:
rotated.push(item)
rotated # [2, 3, 1] for [1, 2, 3]Deque[T] has this surface:
| Item | Signature |
|---|---|
new |
Deque::new() -> Deque[T] |
len, is_empty |
len(self) -> usize; is_empty(self) -> bool |
push_front, push_back |
push_front(&mut self, value: T) -> void, and the same for push_back |
pop_front, pop_back |
pop_front(&mut self) -> T?, and the same for pop_back |
front, back |
front(self) -> T?, and the same for back |
get |
get(self, index: usize) -> T? |
| iteration | Iterable[T] |
| equality | Eq when T < Eq |
Debug |
when T < Debug |
collect |
FromIterator[T] |
- std-collections.deque.collect-surface
std.collectionsdeclaresDeque[T]with private fields, the surface in the table above, and no other method or trait implementation. Code imports it, as inuse std.collections.Deque. - std-collections.deque.orderA deque holds a sequence of elements from its front to its back.
newreturns an empty deque. - std-collections.deque.len
lenreturns the number of elements, andis_emptyis true exactly when that number is 0. - std-collections.deque.push
push_front(value)addsvaluebefore the front, andpush_back(value)adds it after the back. - std-collections.deque.pop
pop_frontremoves the front element and returns it in.Some, andpop_backdoes the same at the back. On an empty deque, each returns.Noneand changes nothing. - std-collections.deque.ends
frontandbackreturn the front and the back element without removing it, or.Nonewhen the deque is empty. - std-collections.deque.get
get(i)returns the elementiplaces from the front in.Some, soget(0)is the front. Anithat is not less thanlengives.None. - std-collections.deque.iterIterating a deque yields its elements from front to back, each as
T. - std-collections.deque.cursorA deque's cursor type is
DequeIter[T], whichstd.collectionsdeclares with private fields. - std-collections.deque.snapshotIterating a deque walks the deque as it was when
iterwas called. A push or a pop while the loop runs changes the deque but not the loop, and never panics, asflow.for.snapshotstates for a list. - std-collections.deque.eqTwo deques are equal when they have the same length and equal elements in the same order from the front, as two lists are.
- std-collections.deque.collectA deque implements
FromIterator[T], collecting every element in source order.
use std.collections.Deque
fn grow(queue: &mut Deque[i32]) -> void:
for item in *queue: # the deque as it was here
queue.push_back(item) # doubles the deque; the loop never panicsNote.
lib/stdbuilds a deque as a ring buffer over aList[T?]. A push into a full buffer first copies the elements into a buffer twice its size. So each push and pop takes amortized constant time, andgettakes constant time.
Why.
getreturns an optional, as Rust'sVecDeque::getdoes: a queue's length changes often, so a missing element is an expected case. A deque is a value, so a loop walks a snapshot of it, as a loop over a list does.
#Heap
A Heap[T] is a binary max-heap, as Rust's BinaryHeap is: pop
removes its largest element.
use std.cmp.Reverse
use std.collections.Heap
fn largest(items: List[i32]) -> i32?:
let mut heap: Heap[i32] = Heap::new()
for item in items:
heap.push(item)
heap.pop() # .Some(9) for [5, 9, 2]
fn smallest(items: List[i32]) -> i32?:
let mut heap: Heap[Reverse[i32]] = Heap::new()
for item in items:
heap.push(Reverse { value: item })
heap.pop().map(fn(top: Reverse[i32]) -> i32: top.value) # .Some(2) for [5, 9, 2]Heap[T < Ord] has this surface:
| Item | Signature |
|---|---|
new |
Heap::new() -> Heap[T] |
len, is_empty |
len(self) -> usize; is_empty(self) -> bool |
push |
push(&mut self, value: T) -> void |
pop |
pop(&mut self) -> T? |
peek |
peek(self) -> T? |
to_sorted_list |
to_sorted_list(self) -> List[T] |
Debug |
when T < Debug |
collect |
FromIterator[T] |
- std-collections.heap.collect-surface
std.collectionsdeclaresHeap[T < Ord]with private fields, the surface in the table above, and no other method or trait implementation. Code imports it, as inuse std.collections.Heap. - std-collections.heap.len
newreturns an empty heap.lenreturns the number of elements, andis_emptyis true exactly when that number is 0. - std-collections.heap.push
push(value)addsvalueto the heap. - std-collections.heap.pop
popremoves a largest element byOrdand returns it in.Some. On an empty heap, it returns.None. - std-collections.heap.peek
peekreturns a largest element without removing it, or.Nonewhen the heap is empty. - std-collections.heap.tiesWhen several elements are equal by
cmp, which of thempopandpeekreturn is not specified. - std-collections.heap.sorted
to_sorted_listreturns a new list of every element in ascending order byOrd, and leaves the heap unchanged. - std-collections.heap.min
stdhas no separate min-heap: aHeap[Reverse[T]]pops the smallestTfirst, bystd-cmp.reverse.order. - std-collections.heap.collectA heap implements
FromIterator[T], collecting every element into a max-heap. - std-collections.heap.collect.linearHeapification of
ncollected elements performs O(n) comparisons, by sifting non-leaves from the bottom up.
Note.
lib/stdkeeps the elements in aList[T?]in heap order, sopushandpoptake logarithmic time andpeekconstant time.
Why.
to_sorted_listcopies, assorted_bydoes, because hd has no consuming methods; its ascending order is that of Rust'sinto_sorted_vec. A heap has noEqand no iteration, as in Rust: two heaps with the same elements may hold them in different orders.
See also: Reverse, Debug For Standard Types.
#List Access And Building
std gives List[T] methods that read one element safely, copy part of
a list, and grow one list by another:
fn second(items: List[string]) -> string?:
items.get(1)
fn preview(lines: List[string]) -> List[string]:
if lines.is_empty():
return ["(empty)"]
lines.take(3)
fn merged(head: List[i32], tail: List[i32]) -> List[i32]:
let mut all: List[i32] = []
all.extend(head.filter(fn(n: i32) -> bool: n > 0))
all.extend(tail)
all.sorted_by(fn(a: i32, b: i32) -> Ordering: b.cmp(a))| Receiver | Methods |
|---|---|
List[T] |
get(self, index: usize) -> T?; is_empty(self) -> bool; first(self) -> T?; last(self) -> T?; take(self, count: usize) -> List[T]; filter(self, keep: fn(T) -> bool) -> List[T]; reversed(self) -> List[T]; sorted_by(self, compare: fn(T, T) -> Ordering) -> List[T]; zip[U](self, other: List[U]) -> List[(T, U)] |
List[T], changing |
extend(&mut self, other: List[T]) -> void |
- std-collections.access.get
get(index)returns.Someof the element atindex, or.Nonewhenindexis not less thanlen(). It never panics. - std-collections.access.is-empty
is_emptyis true exactly whenlen()is 0. - std-collections.access.first-last
firstreturns the element at index 0 andlastthe element at indexlen() - 1, each in.Some. An empty list gives.None. - std-collections.access.take
take(count)returns a new list of the firstcountelements, or of every element whencountis at leastlen(). - std-collections.access.filter
filter(keep)returns a new list of the elements for whichkeepis true, in list order. - std-collections.access.reversed
reversedreturns a new list of the elements in reverse order. - std-collections.access.sorted-by
sorted_by(compare)returns a new list in ascending order bycompare. The sort is stable. - std-collections.access.zip
zip(other)returns a new list of pairs(self[i], other[i])for each indexiof both lists, so it stops at the shorter one. - std-collections.access.extend
extend(other)appends each element ofotherto the receiver, in order, aspushdoes. It changes the length, so it invalidates the list's views bystd-collections.view.invalidate. - std-collections.access.extend.self
items.extend(items)appends a copy of the elementsitemsheld before the call, so it doubles the list. - std-collections.access.helper-rulesThe callbacks of
filterandsorted_byfollowstd-collections.helper.callback-row: each has the empty row.
| Call | Result |
|---|---|
[4, 5].get(1) |
.Some(5) |
[4, 5].get(2) |
.None |
[1, 2, 3].take(2) |
[1, 2] |
[1, 2].take(5) |
[1, 2] |
[1, 2, 3].zip(["a", "b"]) |
[(1, "a"), (2, "b")] |
Why.
getis Rust'sslice::get, the checked read besideitems[i].takeis Kotlin'sList.take: likeList.map, the list method is eager and returns a list, whileIterator.takestays lazy.extendis Rust'sVec::extend, and replacesitems = items + more.
See also: Built-In Methods, Iterator Adapters.