doc-next-gen

Init.Data.Array.Basic

Module docstring

{"### Array literal syntax ","### Preliminary theorems ","### Externs ","### GetElem instance for USize, backed by uget ","### Definitions ","### Lexicographic ordering ","## Auxiliary functions used in metaprogramming.

We do not currently intend to provide verification theorems for these functions. ","### leftpad and rightpad ","### eraseReps ","### allDiff ","### getEvenElems ","### Repr and ToString "}

Array.data abbrev
Full source
@[deprecated toList (since := "2024-09-10")] abbrev data := @toList
Underlying List Representation of an Array
Informal description
The underlying list representation of an array `xs : Array α` is given by `xs.data`, which is of type `List α`. This provides access to the elements of the array as a linked list.
Array.size_set theorem
{xs : Array α} {i : Nat} {v : α} (h : i < xs.size) : (set xs i v h).size = xs.size
Full source
@[simp] theorem size_set {xs : Array α} {i : Nat} {v : α} (h : i < xs.size) :
    (set xs i v h).size = xs.size :=
  List.length_set ..
Size Preservation under Array Element Update
Informal description
For any array `xs` of type `Array α`, any index `i` of type `Nat`, and any value `v` of type `α`, if `i` is less than the size of `xs`, then the size of the array obtained by setting the `i`-th element of `xs` to `v` is equal to the size of `xs`, i.e., $\text{size}(\text{set}(xs, i, v, h)) = \text{size}(xs)$.
Array.size_push theorem
{xs : Array α} (v : α) : (push xs v).size = xs.size + 1
Full source
@[simp] theorem size_push {xs : Array α} (v : α) : (push xs v).size = xs.size + 1 :=
  List.length_concat ..
Size of Array After Push Operation: $\text{size}(\text{push}(xs, v)) = \text{size}(xs) + 1$
Informal description
For any array `xs` of type `Array α` and any element `v` of type `α`, the size of the array obtained by pushing `v` to `xs` is equal to the size of `xs` plus one, i.e., `(push xs v).size = xs.size + 1`.
Array.ext theorem
{xs ys : Array α} (h₁ : xs.size = ys.size) (h₂ : (i : Nat) → (hi₁ : i < xs.size) → (hi₂ : i < ys.size) → xs[i] = ys[i]) : xs = ys
Full source
theorem ext {xs ys : Array α}
    (h₁ : xs.size = ys.size)
    (h₂ : (i : Nat) → (hi₁ : i < xs.size) → (hi₂ : i < ys.size) → xs[i] = ys[i])
    : xs = ys := by
  let rec extAux (as bs : List α)
      (h₁ : as.length = bs.length)
      (h₂ : (i : Nat) → (hi₁ : i < as.length) → (hi₂ : i < bs.length) → as[i] = bs[i])
      : as = bs := by
    induction as generalizing bs with
    | nil =>
      cases bs with
      | nil       => rfl
      | cons b bs => rw [List.length_cons] at h₁; injection h₁
    | cons a as ih =>
      cases bs with
      | nil => rw [List.length_cons] at h₁; injection h₁
      | cons b bs =>
        have hz₁ : 0 < (a::as).length := by rw [List.length_cons]; apply Nat.zero_lt_succ
        have hz₂ : 0 < (b::bs).length := by rw [List.length_cons]; apply Nat.zero_lt_succ
        have headEq : a = b := h₂ 0 hz₁ hz₂
        have h₁' : as.length = bs.length := by rw [List.length_cons, List.length_cons] at h₁; injection h₁
        have h₂' : (i : Nat) → (hi₁ : i < as.length) → (hi₂ : i < bs.length) → as[i] = bs[i] := by
          intro i hi₁ hi₂
          have hi₁' : i+1 < (a::as).length := by rw [List.length_cons]; apply Nat.succ_lt_succ; assumption
          have hi₂' : i+1 < (b::bs).length := by rw [List.length_cons]; apply Nat.succ_lt_succ; assumption
          have : (a::as)[i+1] = (b::bs)[i+1] := h₂ (i+1) hi₁' hi₂'
          apply this
        have tailEq : as = bs := ih bs h₁' h₂'
        rw [headEq, tailEq]
  cases xs; cases ys
  apply congrArg
  apply extAux
  assumption
  assumption
Array Extensionality: Equal Size and Elements Imply Equal Arrays
Informal description
For any two arrays `xs` and `ys` of elements of type `α`, if they have the same size and their corresponding elements at each valid index are equal, then the arrays are equal. More formally, given: 1. `xs.size = ys.size`, and 2. For every natural number index `i` such that `i < xs.size` and `i < ys.size`, we have `xs[i] = ys[i]`, then `xs = ys`.
Array.ext' theorem
{xs ys : Array α} (h : xs.toList = ys.toList) : xs = ys
Full source
theorem ext' {xs ys : Array α} (h : xs.toList = ys.toList) : xs = ys := by
  cases xs; cases ys; simp at h; rw [h]
Array Equality via List Equality
Informal description
For any two arrays `xs` and `ys` of elements of type `α`, if their underlying lists are equal (i.e., `xs.toList = ys.toList`), then the arrays themselves are equal (`xs = ys`).
Array.toArrayAux_eq theorem
{as : List α} {acc : Array α} : (as.toArrayAux acc).toList = acc.toList ++ as
Full source
@[simp] theorem toArrayAux_eq {as : List α} {acc : Array α} : (as.toArrayAux acc).toList = acc.toList ++ as := by
  induction as generalizing acc <;> simp [*, List.toArrayAux, Array.push, List.append_assoc, List.concat_eq_append]
List-to-Array Auxiliary Conversion Preserves Concatenation
Informal description
For any list `as` of elements of type `α` and any array `acc` of elements of type `α`, the list representation of the array obtained by appending `as` to `acc` using `toArrayAux` is equal to the concatenation of the list representation of `acc` and the list `as`. That is, `(as.toArrayAux acc).toList = acc.toList ++ as`.
Array.toArray_toList theorem
{xs : Array α} : xs.toList.toArray = xs
Full source
@[simp] theorem toArray_toList {xs : Array α} : xs.toList.toArray = xs := rfl
Array-List Conversion Identity: `toList.toArray = id`
Informal description
For any array `xs` of elements of type `α`, converting the array to a list and then back to an array yields the original array, i.e., `xs.toList.toArray = xs`.
Array.getElem_toList theorem
{xs : Array α} {i : Nat} (h : i < xs.size) : xs.toList[i] = xs[i]
Full source
@[simp] theorem getElem_toList {xs : Array α} {i : Nat} (h : i < xs.size) : xs.toList[i] = xs[i] := rfl
Array-to-List Conversion Preserves Element Access
Informal description
For any array `xs` of type `Array α` and natural number index `i` such that `i < xs.size`, the `i`-th element of the list obtained by converting `xs` to a list is equal to the `i`-th element of `xs`. In other words, the conversion from array to list preserves element access at valid indices.
Array.getElem?_toList theorem
{xs : Array α} {i : Nat} : xs.toList[i]? = xs[i]?
Full source
@[simp] theorem getElem?_toList {xs : Array α} {i : Nat} : xs.toList[i]? = xs[i]? := by
  simp [getElem?_def]
Optional Element Access Preserved Under Array-to-List Conversion
Informal description
For any array `xs` of type `Array α` and natural number index `i`, the optional element access operation on the list obtained by converting `xs` to a list is equal to the optional element access operation on `xs` itself. That is, `xs.toList[i]? = xs[i]?`.
Array.Mem structure
(as : Array α) (a : α)
Full source
/-- `a ∈ as` is a predicate which asserts that `a` is in the array `as`. -/
-- NB: This is defined as a structure rather than a plain def so that a lemma
-- like `sizeOf_lt_of_mem` will not apply with no actual arrays around.
structure Mem (as : Array α) (a : α) : Prop where
  val : a ∈ as.toList
Membership in an array
Informal description
The predicate `a ∈ as` asserts that an element `a` is contained in the array `as`, which is equivalent to checking if `a` is in the list obtained by converting `as` to a list.
Array.instMembership instance
: Membership α (Array α)
Full source
instance : Membership α (Array α) where
  mem := Mem
Membership Relation for Arrays
Informal description
For any type $\alpha$, the array type `Array α` has a membership relation where an element $a \in \alpha$ is considered to be in an array $as$ if and only if $a$ appears in the list obtained by converting $as$ to a list.
Array.mem_def theorem
{a : α} {as : Array α} : a ∈ as ↔ a ∈ as.toList
Full source
theorem mem_def {a : α} {as : Array α} : a ∈ asa ∈ as ↔ a ∈ as.toList :=
  ⟨fun | .mk h => h, Array.Mem.mk⟩
Membership in Array Equals Membership in Converted List
Informal description
For any element $a$ of type $\alpha$ and any array `as` of type `Array α`, the element $a$ is a member of the array `as` if and only if $a$ is a member of the list obtained by converting `as` to a list.
Array.mem_toArray theorem
{a : α} {l : List α} : a ∈ l.toArray ↔ a ∈ l
Full source
@[simp] theorem mem_toArray {a : α} {l : List α} : a ∈ l.toArraya ∈ l.toArray ↔ a ∈ l := by
  simp [mem_def]
Membership Preservation in List-to-Array Conversion: $a \in l.\text{toArray} \leftrightarrow a \in l$
Informal description
For any element $a$ of type $\alpha$ and any list $l$ of elements of type $\alpha$, the element $a$ is a member of the array obtained by converting $l$ to an array if and only if $a$ is a member of the original list $l$.
Array.getElem_mem theorem
{xs : Array α} {i : Nat} (h : i < xs.size) : xs[i] ∈ xs
Full source
@[simp] theorem getElem_mem {xs : Array α} {i : Nat} (h : i < xs.size) : xs[i]xs[i] ∈ xs := by
  rw [Array.mem_def, ← getElem_toList]
  apply List.getElem_mem
Array Element Membership: $xs[i] \in xs$ when $i < \text{size}(xs)$
Informal description
For any array `xs` of type `Array α` and natural number index `i` such that `i < xs.size`, the element `xs[i]` is a member of the array `xs`.
List.toArray_toList abbrev
Full source
@[deprecated Array.toArray_toList (since := "2025-02-17")]
abbrev toArray_toList := @Array.toArray_toList
List-Array Conversion Identity: `toArray.toList = id`
Informal description
For any list `as` of elements of type `α`, converting the list to an array and then back to a list yields the original list, i.e., `as.toArray.toList = as`.
List.toList_toArray theorem
{as : List α} : as.toArray.toList = as
Full source
theorem toList_toArray {as : List α} : as.toArray.toList = as := rfl
List-Array Conversion Identity: `toArray.toList = id`
Informal description
For any list `as` of elements of type `α`, converting the list to an array and then back to a list yields the original list, i.e., `as.toArray.toList = as`.
Array.toList_toArray abbrev
Full source
@[deprecated toList_toArray (since := "2025-02-17")]
abbrev _root_.Array.toList_toArray := @List.toList_toArray
Array-List Conversion Identity: `toList.toArray = id`
Informal description
For any array `as` of elements of type `α`, converting the array to a list and then back to an array yields the original array, i.e., `as.toList.toArray = as`.
List.size_toArray theorem
{as : List α} : as.toArray.size = as.length
Full source
@[simp] theorem size_toArray {as : List α} : as.toArray.size = as.length := by simp [Array.size]
Array Size Equals List Length After Conversion
Informal description
For any list `as` of elements of type `α`, the size of the array obtained by converting `as` to an array is equal to the length of `as`.
Array.size_toArray abbrev
Full source
@[deprecated size_toArray (since := "2025-02-17")]
abbrev _root_.Array.size_toArray := @List.size_toArray
Preservation of Array Size Through List Conversion
Informal description
For any array `a` of elements of type `α`, the size of the array obtained by converting `a` to a list and then back to an array is equal to the original array's size, i.e., `a.toList.toArray.size = a.size`.
List.getElem_toArray theorem
{xs : List α} {i : Nat} (h : i < xs.toArray.size) : xs.toArray[i] = xs[i]'(by simpa using h)
Full source
@[simp] theorem getElem_toArray {xs : List α} {i : Nat} (h : i < xs.toArray.size) :
    xs.toArray[i] = xs[i]'(by simpa using h) := rfl
Element Preservation in List-to-Array Conversion
Informal description
For any list `xs` of elements of type `α` and natural number index `i` such that `i` is less than the size of the array obtained by converting `xs` to an array, the element at index `i` in the converted array is equal to the element at index `i` in the original list. That is, if `i < (xs.toArray).size`, then `xs.toArray[i] = xs[i]`.
List.getElem?_toArray theorem
{xs : List α} {i : Nat} : xs.toArray[i]? = xs[i]?
Full source
@[simp] theorem getElem?_toArray {xs : List α} {i : Nat} : xs.toArray[i]? = xs[i]? := by
  simp [getElem?_def]
Equality of Optional Element Access in List-to-Array Conversion
Informal description
For any list `xs` of elements of type `α` and any natural number index `i`, the optional element access operation on the array obtained by converting `xs` to an array is equal to the optional element access operation on the original list. That is, `xs.toArray[i]? = xs[i]?`.
List.getElem!_toArray theorem
[Inhabited α] {xs : List α} {i : Nat} : xs.toArray[i]! = xs[i]!
Full source
@[simp] theorem getElem!_toArray [Inhabited α] {xs : List α} {i : Nat} :
    xs.toArray[i]! = xs[i]! := by
  simp [getElem!_def]
Preservation of Panic-Free Element Access in List-to-Array Conversion
Informal description
For any list `xs` of elements of type `α` (where `α` is an inhabited type) and any natural number index `i`, the element accessed via the `!` operator in the array obtained by converting `xs` to an array is equal to the element accessed via the `!` operator in the original list. That is, `xs.toArray[i]! = xs[i]!`.
Array.size_eq_length_toList theorem
{xs : Array α} : xs.size = xs.toList.length
Full source
theorem size_eq_length_toList {xs : Array α} : xs.size = xs.toList.length := rfl
Array Size Equals List Length After Conversion
Informal description
For any array `xs` of type `Array α`, the size of the array (number of elements) is equal to the length of its underlying list representation obtained by converting the array to a list, i.e., $\text{size}(xs) = \text{length}(\text{toList}(xs))$.
Array.data_toArray abbrev
Full source
@[deprecated toList_toArray (since := "2024-09-09")] abbrev data_toArray := @List.toList_toArray
Array-List Conversion Identity: `toArray.data = id`
Informal description
The underlying list representation of an array obtained by converting a list `as` via `List.toArray` is equal to the original list `as`, i.e., `as.toArray.data = as`.
Array.usize definition
(a : @& Array α) : USize
Full source
/--
Returns the size of the array as a platform-native unsigned integer.

This is a low-level version of `Array.size` that directly queries the runtime system's
representation of arrays. While this is not provable, `Array.usize` always returns the exact size of
the array since the implementation only supports arrays of size less than `USize.size`.
-/
@[extern "lean_array_size", simp]
def usize (a : @& Array α) : USize := a.size.toUSize
Array size as unsigned word-size integer
Informal description
The function returns the size of an array `a` as a platform-native unsigned integer, obtained by converting the array's size (as a natural number) to a `USize` value.
Array.uget definition
(a : @& Array α) (i : USize) (h : i.toNat < a.size) : α
Full source
/--
Low-level indexing operator which is as fast as a C array read.

This avoids overhead due to unboxing a `Nat` used as an index.
-/
@[extern "lean_array_uget", simp]
def uget (a : @& Array α) (i : USize) (h : i.toNat < a.size) : α :=
  a[i.toNat]
Fast array indexing with unsigned index
Informal description
The function retrieves the element at index `i` (given as a platform-dependent unsigned word-size integer) from array `a`, provided that the natural number representation of `i` is less than the size of `a`. This operation is optimized to be as fast as a C array read, avoiding overhead from unboxing natural numbers.
Array.uset definition
(xs : Array α) (i : USize) (v : α) (h : i.toNat < xs.size) : Array α
Full source
/--
Low-level modification operator which is as fast as a C array write. The modification is performed
in-place when the reference to the array is unique.

This avoids overhead due to unboxing a `Nat` used as an index.
-/
@[extern "lean_array_uset"]
def uset (xs : Array α) (i : USize) (v : α) (h : i.toNat < xs.size) : Array α :=
  xs.set i.toNat v h
In-place array modification at unsigned index
Informal description
The function modifies the element at index `i` (given as a platform-dependent unsigned word-size integer) in the array `xs` to the value `v`, under the condition that the index is within bounds (i.e., `i.toNat < xs.size`). The operation is performed in-place when the array reference is unique, making it as efficient as a C array write.
Array.pop definition
(xs : Array α) : Array α
Full source
/--
Removes the last element of an array. If the array is empty, then it is returned unmodified. The
modification is performed in-place when the reference to the array is unique.

Examples:
* `#[1, 2, 3].pop = #[1, 2]`
* `#["orange", "yellow"].pop = #["orange"]`
* `(#[] : Array String).pop = #[]`
-/
@[extern "lean_array_pop"]
def pop (xs : Array α) : Array α where
  toList := xs.toList.dropLast
Array pop operation
Informal description
The function removes the last element of an array `xs` of type `Array α`. If the array is empty, it returns the array unchanged. The operation is performed in-place when the array reference is unique. For example: - `#[1, 2, 3].pop` returns `#[1, 2]` - `#["orange", "yellow"].pop` returns `#["orange"]` - `(#[] : Array String).pop` returns `#[]`
Array.size_pop theorem
{xs : Array α} : xs.pop.size = xs.size - 1
Full source
@[simp] theorem size_pop {xs : Array α} : xs.pop.size = xs.size - 1 := by
  match xs with
  | ⟨[]⟩ => rfl
  | ⟨a::as⟩ => simp [pop, Nat.succ_sub_succ_eq_sub, size]
Size Reduction by One After Array Pop Operation
Informal description
For any array `xs` of type `Array α`, the size of the array obtained by removing its last element (`xs.pop`) is equal to the original size minus one, i.e., $\text{size}(\text{xs.pop}) = \text{size}(\text{xs}) - 1$.
Array.replicate definition
{α : Type u} (n : Nat) (v : α) : Array α
Full source
/--
Creates an array that contains `n` repetitions of `v`.

The corresponding `List` function is `List.replicate`.

Examples:
 * `Array.replicate 2 true = #[true, true]`
 * `Array.replicate 3 () = #[(), (), ()]`
 * `Array.replicate 0 "anything" = #[]`
-/
@[extern "lean_mk_array"]
def replicate {α : Type u} (n : Nat) (v : α) : Array α where
  toList := List.replicate n v
Array replication function
Informal description
The function creates an array of length $n$ where every element is equal to $v$. For example, `Array.replicate 2 true` produces the array `#[true, true]`, and `Array.replicate 0 "anything"` produces the empty array `#[]`.
Array.mkArray definition
{α : Type u} (n : Nat) (v : α) : Array α
Full source
/--
Creates an array that contains `n` repetitions of `v`.

The corresponding `List` function is `List.replicate`.

Examples:
 * `Array.mkArray 2 true = #[true, true]`
 * `Array.mkArray 3 () = #[(), (), ()]`
 * `Array.mkArray 0 "anything" = #[]`
-/
@[extern "lean_mk_array", deprecated replicate (since := "2025-03-18")]
def mkArray {α : Type u} (n : Nat) (v : α) : Array α where
  toList := List.replicate n v
Array constructor with repeated elements
Informal description
The function creates an array of length $n$ where every element is equal to $v$. For example, `Array.mkArray 2 true` produces the array `#[true, true]`, and `Array.mkArray 0 "anything"` produces the empty array `#[]`.
Array.size_swap theorem
{xs : Array α} {i j : Nat} {hi hj} : (xs.swap i j hi hj).size = xs.size
Full source
@[simp] theorem size_swap {xs : Array α} {i j : Nat} {hi hj} : (xs.swap i j hi hj).size = xs.size := by
  show ((xs.set i xs[j]).set j xs[i]
    (Nat.lt_of_lt_of_eq hj (size_set _).symm)).size = xs.size
  rw [size_set, size_set]
Size Preservation under Array Element Swap
Informal description
For any array `xs` of type `Array α` and indices `i, j` of type `Nat` with proofs `hi : i < xs.size` and `hj : j < xs.size`, the size of the array obtained by swapping elements at positions `i` and `j` in `xs` is equal to the size of `xs`, i.e., $\text{size}(\text{swap}(xs, i, j, hi, hj)) = \text{size}(xs)$.
Array.swapIfInBounds definition
(xs : Array α) (i j : @& Nat) : Array α
Full source
/--
Swaps two elements of an array, returning the array unchanged if either index is out of bounds. The
modification is performed in-place when the reference to the array is unique.

Examples:
* `#["red", "green", "blue", "brown"].swapIfInBounds 0 3 = #["brown", "green", "blue", "red"]`
* `#["red", "green", "blue", "brown"].swapIfInBounds 0 2 = #["blue", "green", "red", "brown"]`
* `#["red", "green", "blue", "brown"].swapIfInBounds 1 2 = #["red", "blue", "green", "brown"]`
* `#["red", "green", "blue", "brown"].swapIfInBounds 0 4 = #["red", "green", "blue", "brown"]`
* `#["red", "green", "blue", "brown"].swapIfInBounds 9 2 = #["red", "green", "blue", "brown"]`
-/
@[extern "lean_array_swap"]
def swapIfInBounds (xs : Array α) (i j : @& Nat) : Array α :=
  if h₁ : i < xs.size then
  if h₂ : j < xs.size then swap xs i j
  else xs
  else xs
Conditional array element swap
Informal description
Given an array `xs` of type `α` and two indices `i` and `j`, the function swaps the elements at positions `i` and `j` if both indices are within the bounds of the array (i.e., `i < xs.size` and `j < xs.size`). If either index is out of bounds, the function returns the original array unchanged. The swap is performed in-place when the array reference is unique.
Array.swap! abbrev
Full source
@[deprecated swapIfInBounds (since := "2024-11-24")] abbrev swap! := @swapIfInBounds
In-place Array Element Swap Operation
Informal description
Given an array `xs` of type `Array α` and two indices `i` and `j`, the operation `swap!` performs an in-place swap of the elements at positions `i` and `j` if both indices are within the bounds of the array (i.e., `i < xs.size` and `j < xs.size`). If either index is out of bounds, the operation leaves the array unchanged.
Array.instGetElemUSizeLtNatToNatSize instance
: GetElem (Array α) USize α fun xs i => i.toNat < xs.size
Full source
instance : GetElem (Array α) USize α fun xs i => i.toNat < xs.size where
  getElem xs i h := xs.uget i h
Array Indexing with Unsigned Word-Size Indices
Informal description
For any type $\alpha$, arrays of type `Array α` can be indexed using platform-dependent unsigned word-size integers `USize`, where the validity condition for indexing requires that the natural number representation of the index is less than the size of the array.
Array.instEmptyCollection instance
: EmptyCollection (Array α)
Full source
instance : EmptyCollection (Array α) := ⟨Array.empty⟩
Empty Array as Empty Collection
Informal description
For any type $\alpha$, the type `Array α` of dynamic arrays over $\alpha$ has an empty collection, denoted by $\emptyset$ or $\{\}$.
Array.instInhabited instance
: Inhabited (Array α)
Full source
instance : Inhabited (Array α) where
  default := Array.empty
Arrays are Inhabited Types
Informal description
For any type $\alpha$, the type of arrays with elements of type $\alpha$ is inhabited, with the empty array as its default element.
Array.isEmpty definition
(xs : Array α) : Bool
Full source
/--
Checks whether an array is empty.

An array is empty if its size is `0`.

Examples:
 * `(#[] : Array String).isEmpty = true`
 * `#[1, 2].isEmpty = false`
 * `#[()].isEmpty = false`
-/
def isEmpty (xs : Array α) : Bool :=
  xs.size = 0
Array emptiness check
Informal description
The function checks whether an array `xs` of type `Array α` is empty by verifying if its size is equal to 0.
Array.isEqvAux definition
(xs ys : Array α) (hsz : xs.size = ys.size) (p : α → α → Bool) : ∀ (i : Nat) (_ : i ≤ xs.size), Bool
Full source
@[specialize]
def isEqvAux (xs ys : Array α) (hsz : xs.size = ys.size) (p : α → α → Bool) :
    ∀ (i : Nat) (_ : i ≤ xs.size), Bool
  | 0, _ => true
  | i+1, h =>
    p xs[i] (ys[i]'(hsz ▸ h)) && isEqvAux xs ys hsz p i (Nat.le_trans (Nat.le_add_right i 1) h)
Array equivalence check (auxiliary function)
Informal description
The auxiliary function `isEqvAux` checks whether two arrays `xs` and `ys` of the same size (ensured by `hsz : xs.size = ys.size`) are element-wise equivalent up to index `i` using a given predicate `p : α → α → Bool`. The function recursively verifies that all elements up to index `i` satisfy `p`, starting from the end of the arrays and moving backward. Specifically: - Base case: When `i = 0`, the arrays are trivially equivalent. - Inductive step: For `i+1`, it checks that `p` holds for the `i`-th elements of both arrays and recursively verifies the equivalence for the remaining indices.
Array.isEqv definition
(xs ys : Array α) (p : α → α → Bool) : Bool
Full source
/--
Returns `true` if `as` and `bs` have the same length and they are pairwise related by `eqv`.

Short-circuits at the first non-related pair of elements.

Examples:
* `#[1, 2, 3].isEqv #[2, 3, 4] (· < ·) = true`
* `#[1, 2, 3].isEqv #[2, 2, 4] (· < ·) = false`
* `#[1, 2, 3].isEqv #[2, 3] (· < ·) = false`
-/
@[inline] def isEqv (xs ys : Array α) (p : α → α → Bool) : Bool :=
  if h : xs.size = ys.size then
    isEqvAux xs ys h p xs.size (Nat.le_refl xs.size)
  else
    false
Array element-wise equivalence check
Informal description
The function checks whether two arrays `xs` and `ys` of type `Array α` have the same length and whether all corresponding elements satisfy a given binary predicate `p : α → α → Bool`. The function returns `true` if both conditions are met, and `false` otherwise. The evaluation short-circuits at the first pair of elements that does not satisfy `p`. Examples: - `#[1, 2, 3].isEqv #[2, 3, 4] (· < ·)` evaluates to `true` because each element in the first array is less than the corresponding element in the second array. - `#[1, 2, 3].isEqv #[2, 2, 4] (· < ·)` evaluates to `false` because the second elements (2 and 2) are not related by `<`. - `#[1, 2, 3].isEqv #[2, 3] (· < ·)` evaluates to `false` because the arrays have different lengths.
Array.instBEq instance
[BEq α] : BEq (Array α)
Full source
instance [BEq α] : BEq (Array α) :=
  ⟨fun xs ys => isEqv xs ys BEq.beq⟩
Element-wise Boolean Equality for Arrays
Informal description
For any type $\alpha$ equipped with a boolean equality relation `==`, the type `Array α` of dynamic arrays over $\alpha$ can be equipped with a boolean equality relation that checks element-wise equality using the given relation on $\alpha$.
Array.ofFn definition
{n} (f : Fin n → α) : Array α
Full source
/--
Creates an array by applying `f` to each potential index in order, starting at `0`.

Examples:
 * `Array.ofFn (n := 3) toString = #["0", "1", "2"]`
 * `Array.ofFn (fun i => #["red", "green", "blue"].get i.val i.isLt) = #["red", "green", "blue"]`
-/
def ofFn {n} (f : Fin n → α) : Array α := go 0 (emptyWithCapacity n) where
  /-- Auxiliary for `ofFn`. `ofFn.go f i acc = acc ++ #[f i, ..., f(n - 1)]` -/
  @[semireducible] -- This is otherwise irreducible because it uses well-founded recursion.
  go (i : Nat) (acc : Array α) : Array α :=
    if h : i < n then go (i+1) (acc.push (f ⟨i, h⟩)) else acc
  decreasing_by simp_wf; decreasing_trivial_pre_omega
Array construction from a function on indices
Informal description
Given a natural number $n$ and a function $f$ that maps each index $i$ (where $0 \leq i < n$) to an element of type $\alpha$, the function `Array.ofFn` constructs an array of length $n$ where the $i$-th element is $f(i)$. For example: - `Array.ofFn (n := 3) toString` produces `#["0", "1", "2"]` - `Array.ofFn (fun i => #["red", "green", "blue"].get i.val i.isLt)` produces `#["red", "green", "blue"]`
Array.range definition
(n : Nat) : Array Nat
Full source
/--
Constructs an array that contains all the numbers from `0` to `n`, exclusive.

Examples:
 * `Array.range 5 := #[0, 1, 2, 3, 4]`
 * `Array.range 0 := #[]`
 * `Array.range 1 := #[0]`
-/
def range (n : Nat) : Array Nat :=
  ofFn fun (i : Fin n) => i
Array of natural numbers from 0 to n-1
Informal description
The function constructs an array of natural numbers from `0` to `n-1`. For example: - `Array.range 5` produces `#[0, 1, 2, 3, 4]` - `Array.range 0` produces `#[]` - `Array.range 1` produces `#[0]`
Array.singleton definition
(v : α) : Array α
Full source
/--
Constructs a single-element array that contains `v`.

Examples:
 * `Array.singleton 5 = #[5]`
 * `Array.singleton "one" = #["one"]`
-/
@[inline] protected def singleton (v : α) : Array α := #[v]
Singleton array constructor
Informal description
The function constructs an array containing a single element `v` of type `α`. For example, `Array.singleton 5` produces the array `#[5]`.
Array.back! definition
[Inhabited α] (xs : Array α) : α
Full source
/--
Returns the last element of an array, or panics if the array is empty.

Safer alternatives include `Array.back`, which requires a proof the array is non-empty, and
`Array.back?`, which returns an `Option`.
-/
def back! [Inhabited α] (xs : Array α) : α :=
  xs[xs.size - 1]!
Last element of an array (unsafe)
Informal description
The function returns the last element of an array `xs` of type `α`, or panics if the array is empty. If the array is non-empty, it returns the element at index `xs.size - 1`.
Array.back? definition
(xs : Array α) : Option α
Full source
/--
Returns the last element of an array, or `none` if the array is empty.

See `Array.back!` for the version that panics if the array is empty, or `Array.back` for the version
that requires a proof the array is non-empty.
-/
def back? (xs : Array α) : Option α :=
  xs[xs.size - 1]?
Optional last element of an array
Informal description
The function returns the last element of an array `xs` as an optional value of type `Option α`. If the array is non-empty, it returns `some x` where `x` is the last element; otherwise, it returns `none`.
Array.get? definition
(xs : Array α) (i : Nat) : Option α
Full source
@[deprecated "Use `a[i]?` instead." (since := "2025-02-12")]
def get? (xs : Array α) (i : Nat) : Option α :=
  if h : i < xs.size then some xs[i] else none
Optional array element at index
Informal description
The function takes an array `xs` of type `α` and a natural number index `i`, and returns an optional value of type `Option α`. If the index `i` is within bounds (i.e., `i < xs.size`), it returns `some xs[i]`; otherwise, it returns `none`.
Array.swapAt! definition
(xs : Array α) (i : Nat) (v : α) : α × Array α
Full source
/--
Swaps a new element with the element at the given index. Panics if the index is out of bounds.

Returns the value formerly found at `i`, paired with an array in which the value at `i` has been
replaced with `v`.

Examples:
* `#["spinach", "broccoli", "carrot"].swapAt! 1 "pepper" = (#["spinach", "pepper", "carrot"], "broccoli")`
* `#["spinach", "broccoli", "carrot"].swapAt! 2 "pepper" = (#["spinach", "broccoli", "pepper"], "carrot")`
-/
@[inline]
def swapAt! (xs : Array α) (i : Nat) (v : α) : α × Array α :=
  if h : i < xs.size then
    swapAt xs i v
  else
    have : Inhabited (α × Array α) := ⟨(v, xs)⟩
    panic! ("index " ++ toString i ++ " out of bounds")
Array element swap at index
Informal description
Given an array `xs` of type `α`, an index `i`, and a value `v` of type `α`, the function returns a pair consisting of the original value at index `i` and a new array where the element at index `i` has been replaced with `v`. If the index `i` is out of bounds (i.e., `i ≥ xs.size`), the function panics with an error message.
Array.shrink definition
(xs : Array α) (n : Nat) : Array α
Full source
/--
Returns the first `n` elements of an array. The resulting array is produced by repeatedly calling
`Array.pop`. If `n` is greater than the size of the array, it is returned unmodified.

If the reference to the array is unique, then this function uses in-place modification.

Examples:
* `#[0, 1, 2, 3, 4].shrink 2 = #[0, 1]`
* `#[0, 1, 2, 3, 4].shrink 0 = #[]`
* `#[0, 1, 2, 3, 4].shrink 10 = #[0, 1, 2, 3, 4]`
-/
def shrink (xs : Array α) (n : Nat) : Array α :=
  let rec loop
    | 0,   xs => xs
    | n+1, xs => loop n xs.pop
  loop (xs.size - n) xs
Truncate array to first `n` elements
Informal description
Given an array `xs` of type `α` and a natural number `n`, the function returns a new array consisting of the first `n` elements of `xs`. If `n` is greater than the size of `xs`, the original array is returned unchanged. The operation is performed by repeatedly removing elements from the end of the array until the desired size is reached.
Array.take abbrev
(xs : Array α) (i : Nat) : Array α
Full source
/--
Returns a new array that contains the first `i` elements of `xs`. If `xs` has fewer than `i`
elements, the new array contains all the elements of `xs`.

The returned array is always a new array, even if it contains the same elements as the input array.

Examples:
* `#["red", "green", "blue"].take 1 = #["red"]`
* `#["red", "green", "blue"].take 2 = #["red", "green"]`
* `#["red", "green", "blue"].take 5 = #["red", "green", "blue"]`
-/
abbrev take (xs : Array α) (i : Nat) : Array α := extract xs 0 i
Take first `i` elements of an array
Informal description
Given an array `xs` of elements of type `α` and a natural number `i`, the function returns a new array containing the first `i` elements of `xs`. If `xs` has fewer than `i` elements, the new array contains all elements of `xs`.
Array.take_eq_extract theorem
{xs : Array α} {i : Nat} : xs.take i = xs.extract 0 i
Full source
@[simp] theorem take_eq_extract {xs : Array α} {i : Nat} : xs.take i = xs.extract 0 i := rfl
Equivalence of Array Take and Extract Operations
Informal description
For any array `xs` of type `Array α` and any natural number `i`, taking the first `i` elements of `xs` is equivalent to extracting the subarray from index `0` to `i` of `xs`. That is, $\text{take}(xs, i) = \text{extract}(xs, 0, i)$.
Array.drop abbrev
(xs : Array α) (i : Nat) : Array α
Full source
/--
Removes the first `i` elements of `xs`. If `xs` has fewer than `i` elements, the new array is empty.

The returned array is always a new array, even if it contains the same elements as the input array.

Examples:
* `#["red", "green", "blue"].drop 1 = #["green", "blue"]`
* `#["red", "green", "blue"].drop 2 = #["blue"]`
* `#["red", "green", "blue"].drop 5 = #[]`
-/
abbrev drop (xs : Array α) (i : Nat) : Array α := extract xs i xs.size
Array Drop Operation
Informal description
Given an array `xs` of type `Array α` and a natural number `i`, the function `Array.drop` returns a new array consisting of the elements of `xs` with the first `i` elements removed. If `xs` has fewer than `i` elements, the result is an empty array. **Examples:** - `#["red", "green", "blue"].drop 1 = #["green", "blue"]` - `#["red", "green", "blue"].drop 2 = #["blue"]` - `#["red", "green", "blue"].drop 5 = #[]`
Array.drop_eq_extract theorem
{xs : Array α} {i : Nat} : xs.drop i = xs.extract i xs.size
Full source
@[simp] theorem drop_eq_extract {xs : Array α} {i : Nat} : xs.drop i = xs.extract i xs.size := rfl
Equality of Array Drop and Extract Operations: `drop i = extract i size`
Informal description
For any array `xs` of type `Array α` and any natural number `i`, the operation `xs.drop i` is equal to `xs.extract i xs.size`. Here, `xs.drop i` returns the array with the first `i` elements removed, while `xs.extract i xs.size` returns the subarray starting at index `i` and ending at the end of the array.
Array.modifyMUnsafe definition
[Monad m] (xs : Array α) (i : Nat) (f : α → m α) : m (Array α)
Full source
@[inline]
unsafe def modifyMUnsafe [Monad m] (xs : Array α) (i : Nat) (f : α → m α) : m (Array α) := do
  if h : i < xs.size then
    let v                := xs[i]
    -- Replace a[i] by `box(0)`.  This ensures that `v` remains unshared if possible.
    -- Note: we assume that arrays have a uniform representation irrespective
    -- of the element type, and that it is valid to store `box(0)` in any array.
    let xs'               := xs.set i (unsafeCast ())
    let v ← f v
    pure <| xs'.set i v (Nat.lt_of_lt_of_eq h (size_set ..).symm)
  else
    pure xs
Unsafe monadic array modification at index
Informal description
Given a monad `m`, an array `xs` of type `Array α`, an index `i` of type `Nat`, and a monadic function `f : α → m α`, the function `Array.modifyMUnsafe` modifies the element at index `i` in `xs` by applying `f` to it, returning the modified array in the monadic context. If the index `i` is out of bounds (i.e., `i ≥ xs.size`), the original array is returned unchanged. The operation is marked as "unsafe" because it uses internal optimizations that assume the array is unshared, allowing for in-place updates when possible.
Array.modifyM definition
[Monad m] (xs : Array α) (i : Nat) (f : α → m α) : m (Array α)
Full source
/--
Replaces the element at the given index, if it exists, with the result of applying the monadic
function `f` to it. If the index is invalid, the array is returned unmodified and `f` is not called.

Examples:
```lean example
#eval #[1, 2, 3, 4].modifyM 2 fun x => do
  IO.println s!"It was {x}"
  return x * 10
```
```output
It was 3
```
```output
#[1, 2, 30, 4]
```

```lean example
#eval #[1, 2, 3, 4].modifyM 6 fun x => do
  IO.println s!"It was {x}"
  return x * 10
```
```output
#[1, 2, 3, 4]
```
-/
@[implemented_by modifyMUnsafe]
def modifyM [Monad m] (xs : Array α) (i : Nat) (f : α → m α) : m (Array α) := do
  if h : i < xs.size then
    let v   := xs[i]
    let v ← f v
    pure <| xs.set i v
  else
    pure xs
Monadic array modification at index
Informal description
Given a monad `m`, an array `xs` of type `Array α`, an index `i`, and a monadic function `f : α → m α`, this function modifies the array by applying `f` to the element at index `i` (if `i` is within bounds) and replacing it with the result. If the index is out of bounds, the array is returned unchanged. More formally, if `i < xs.size`, then `xs.modifyM i f` returns a new array where the `i`-th element is replaced by `f xs[i]`. Otherwise, it returns `xs` unchanged.
Array.modify definition
(xs : Array α) (i : Nat) (f : α → α) : Array α
Full source
/--
Replaces the element at the given index, if it exists, with the result of applying `f` to it. If the
index is invalid, the array is returned unmodified.

Examples:
 * `#[1, 2, 3].modify 0 (· * 10) = #[10, 2, 3]`
 * `#[1, 2, 3].modify 2 (· * 10) = #[1, 2, 30]`
 * `#[1, 2, 3].modify 3 (· * 10) = #[1, 2, 3]`
-/
@[inline]
def modify (xs : Array α) (i : Nat) (f : α → α) : Array α :=
  Id.run <| modifyM xs i f
Array modification at index
Informal description
Given an array `xs` of type `Array α`, an index `i`, and a function `f : α → α`, this function modifies the array by applying `f` to the element at index `i` (if `i` is within bounds) and replacing it with the result. If the index is out of bounds, the array is returned unchanged. More formally, if `i < xs.size`, then `xs.modify i f` returns a new array where the `i`-th element is replaced by `f xs[i]`. Otherwise, it returns `xs` unchanged.
Array.modifyOp definition
(xs : Array α) (idx : Nat) (f : α → α) : Array α
Full source
/--
Replaces the element at the given index, if it exists, with the result of applying `f` to it. If the
index is invalid, the array is returned unmodified.

Examples:
 * `#[1, 2, 3].modifyOp 0 (· * 10) = #[10, 2, 3]`
 * `#[1, 2, 3].modifyOp 2 (· * 10) = #[1, 2, 30]`
 * `#[1, 2, 3].modifyOp 3 (· * 10) = #[1, 2, 3]`
-/
@[inline]
def modifyOp (xs : Array α) (idx : Nat) (f : α → α) : Array α :=
  xs.modify idx f
Array modification at index (operator version)
Informal description
Given an array `xs` of type `Array α`, an index `idx`, and a function `f : α → α`, this function modifies the array by applying `f` to the element at index `idx` (if `idx` is within bounds) and replacing it with the result. If the index is out of bounds, the array is returned unchanged. More formally, if `idx < xs.size`, then `xs.modifyOp idx f` returns a new array where the `idx`-th element is replaced by `f xs[idx]`. Otherwise, it returns `xs` unchanged.
Array.forIn' definition
{α : Type u} {β : Type v} {m : Type v → Type w} [Monad m] (as : Array α) (b : β) (f : (a : α) → a ∈ as → β → m (ForInStep β)) : m β
Full source
/-- Reference implementation for `forIn'` -/
@[implemented_by Array.forIn'Unsafe]
protected def forIn' {α : Type u} {β : Type v} {m : Type v → Type w} [Monad m] (as : Array α) (b : β) (f : (a : α) → a ∈ as → β → m (ForInStep β)) : m β :=
  let rec loop (i : Nat) (h : i ≤ as.size) (b : β) : m β := do
    match i, h with
    | 0,   _ => pure b
    | i+1, h =>
      have h' : i < as.size            := Nat.lt_of_lt_of_le (Nat.lt_succ_self i) h
      have : as.size - 1 < as.size     := Nat.sub_lt (Nat.zero_lt_of_lt h') (by decide)
      have : as.size - 1 - i < as.size := Nat.lt_of_le_of_lt (Nat.sub_le (as.size - 1) i) this
      match (← f as[as.size - 1 - i] (getElem_mem this) b) with
      | ForInStep.done b  => pure b
      | ForInStep.yield b => loop i (Nat.le_of_lt h') b
  loop as.size (Nat.le_refl _) b
Monadic array iteration (reverse order)
Informal description
The function `Array.forIn'` implements iteration over an array `as` of type `α` in a monadic context `m`. Starting with an initial state `b` of type `β`, it applies a function `f` to each element `a` of the array (along with a proof that `a` is in `as`) and the current state, producing a monadic action that returns either `ForInStep.yield` to continue iteration with an updated state or `ForInStep.done` to terminate early with a final state. The iteration proceeds from the last element to the first.
Array.instForIn'InferInstanceMembership instance
: ForIn' m (Array α) α inferInstance
Full source
instance : ForIn' m (Array α) α inferInstance where
  forIn' := Array.forIn'
Monadic Iteration with Membership Proofs for Arrays
Informal description
For any monad `m` and type `α`, the array type `Array α` supports monadic iteration with membership proofs, where elements of type `α` can be iterated over with proofs that they belong to the array.
Array.forIn'_eq_forIn' theorem
[Monad m] : @Array.forIn' α β m _ = forIn'
Full source
@[simp] theorem forIn'_eq_forIn' [Monad m] : @Array.forIn' α β m _ = forIn' := rfl
Equality of Array Iteration Functions in a Monadic Context
Informal description
For any monad `m`, the function `Array.forIn'` is equal to `forIn'` when specialized to arrays.
Array.mapM definition
{α : Type u} {β : Type v} {m : Type v → Type w} [Monad m] (f : α → m β) (as : Array α) : m (Array β)
Full source
/--
Applies the monadic action `f` to every element in the array, left-to-right, and returns the array
of results.
-/
-- Reference implementation for `mapM`
@[implemented_by mapMUnsafe]
def mapM {α : Type u} {β : Type v} {m : Type v → Type w} [Monad m] (f : α → m β) (as : Array α) : m (Array β) :=
  -- Note: we cannot use `foldlM` here for the reference implementation because this calls
  -- `bind` and `pure` too many times. (We are not assuming `m` is a `LawfulMonad`)
  let rec @[semireducible] -- This is otherwise irreducible because it uses well-founded recursion.
    map (i : Nat) (bs : Array β) : m (Array β) := do
      if hlt : i < as.size then
        map (i+1) (bs.push (← f as[i]))
      else
        pure bs
  decreasing_by simp_wf; decreasing_trivial_pre_omega
  map 0 (emptyWithCapacity as.size)
Monadic map over array elements
Informal description
Given a monad `m`, a function `f : α → m β`, and an array `as : Array α`, the function `Array.mapM` applies `f` to each element of `as` in left-to-right order, collecting the results in a new array of type `Array β` within the monadic context `m`.
Array.sequenceMap abbrev
Full source
@[deprecated mapM (since := "2024-11-11")] abbrev sequenceMap := @mapM
Monadic Sequence Mapping for Arrays
Informal description
Given a monad `m` and an array `as : Array (m α)`, the function `Array.sequenceMap` sequences the monadic computations in `as` from left to right, collecting their results in a new array of type `Array α` within the monadic context `m`.
Array.mapFinIdxM definition
{α : Type u} {β : Type v} {m : Type v → Type w} [Monad m] (as : Array α) (f : (i : Nat) → α → (h : i < as.size) → m β) : m (Array β)
Full source
/--
Applies the monadic action `f` to every element in the array, along with the element's index and a
proof that the index is in bounds, from left to right. Returns the array of results.
-/
@[inline]
def mapFinIdxM {α : Type u} {β : Type v} {m : Type v → Type w} [Monad m]
    (as : Array α) (f : (i : Nat) → α → (h : i < as.size) → m β) : m (Array β) :=
  let rec @[specialize] map (i : Nat) (j : Nat) (inv : i + j = as.size) (bs : Array β) : m (Array β) := do
    match i, inv with
    | 0,    _  => pure bs
    | i+1, inv =>
      have j_lt : j < as.size := by
        rw [← inv, Nat.add_assoc, Nat.add_comm 1 j, Nat.add_comm]
        apply Nat.le_add_right
      have : i + (j + 1) = as.size := by rw [← inv, Nat.add_comm j 1, Nat.add_assoc]
      map i (j+1) this (bs.push (← f j as[j] j_lt))
  map as.size 0 rfl (emptyWithCapacity as.size)
Monadic map over array elements with bounded indices
Informal description
Given a monad `m`, an array `as : Array α`, and a function `f` that takes an index `i`, an element of the array, and a proof that `i` is within the bounds of `as`, the function `Array.mapFinIdxM` applies `f` to each element of `as` from left to right, collecting the results in a new array of type `Array β` within the monadic context `m`. The function ensures that the index `i` is always valid when accessing elements of `as`.
Array.mapIdxM definition
{α : Type u} {β : Type v} {m : Type v → Type w} [Monad m] (f : Nat → α → m β) (as : Array α) : m (Array β)
Full source
/--
Applies the monadic action `f` to every element in the array, along with the element's index, from
left to right. Returns the array of results.
-/
@[inline]
def mapIdxM {α : Type u} {β : Type v} {m : Type v → Type w} [Monad m] (f : Nat → α → m β) (as : Array α) : m (Array β) :=
  as.mapFinIdxM fun i a _ => f i a
Monadic map over array elements with indices
Informal description
Given a monad `m`, an array `as : Array α`, and a function `f` that takes an index `i` and an element of the array, the function `Array.mapIdxM` applies `f` to each element of `as` from left to right, collecting the results in a new array of type `Array β` within the monadic context `m`.
Array.firstM definition
{α : Type u} {m : Type v → Type w} [Alternative m] (f : α → m β) (as : Array α) : m β
Full source
/--
Maps `f` over the array and collects the results with `<|>`. The result for the end of the array is
`failure`.

Examples:
 * `#[[], [1, 2], [], [2]].firstM List.head? = some 1`
 * `#[[], [], []].firstM List.head? = none`
 * `#[].firstM List.head? = none`
-/
@[inline]
def firstM {α : Type u} {m : Type v → Type w} [Alternative m] (f : α → m β) (as : Array α) : m β :=
  go 0
where
  go (i : Nat) : m β :=
    if hlt : i < as.size then
      f as[i] <|> go (i+1)
    else
      failure
  termination_by as.size - i
  decreasing_by exact Nat.sub_succ_lt_self as.size i hlt
First successful monadic application over an array
Informal description
Given a monad `m` with an `Alternative` instance, an array `as : Array α`, and a function `f : α → m β`, the function `Array.firstM` applies `f` to each element of `as` from left to right until it succeeds (i.e., returns a value in `m β`). If all applications of `f` result in `failure`, the function returns `failure`.
Array.findSomeM? definition
{α : Type u} {β : Type v} {m : Type v → Type w} [Monad m] (f : α → m (Option β)) (as : Array α) : m (Option β)
Full source
/--
Returns the first non-`none` result of applying the monadic function `f` to each element of the
array, in order. Returns `none` if `f` returns `none` for all elements.

Example:
```lean example
#eval #[7, 6, 5, 8, 1, 2, 6].findSomeM? fun i => do
  if i < 5 then
    return some (i * 10)
  if i ≤ 6 then
    IO.println s!"Almost! {i}"
  return none
```
```output
Almost! 6
Almost! 5
```
```output
some 10
```
-/
@[inline]
def findSomeM? {α : Type u} {β : Type v} {m : Type v → Type w} [Monad m] (f : α → m (Option β)) (as : Array α) : m (Option β) := do
  for a in as do
    match (← f a) with
    | some b => return b
    | _      => pure ⟨⟩
  return none
Monadic find-first-some operation on arrays
Informal description
Given a monad `m`, an array `as : Array α`, and a function `f : α → m (Option β)`, the function `Array.findSomeM?` applies `f` to each element of `as` in order until it finds the first element where `f` returns `some b`. It then returns `some b` in the monadic context `m`. If no such element is found, it returns `none`.
Array.findM? definition
{α : Type} [Monad m] (p : α → m Bool) (as : Array α) : m (Option α)
Full source
/--
Returns the first element of the array for which the monadic predicate `p` returns `true`, or `none`
if no such element is found. Elements of the array are checked in order.

The monad `m` is restricted to `Type → Type` to avoid needing to use `ULift Bool` in `p`'s type.

Example:
```lean example
#eval #[7, 6, 5, 8, 1, 2, 6].findM? fun i => do
  if i < 5 then
    return true
  if i ≤ 6 then
    IO.println s!"Almost! {i}"
  return false
```
```output
Almost! 6
Almost! 5
```
```output
some 1
```
-/
@[inline]
def findM? {α : Type} [Monad m] (p : α → m Bool) (as : Array α) : m (Option α) := do
  for a in as do
    if (← p a) then
      return a
  return none
Monadic find-first in array
Informal description
Given a monadic predicate \( p : \alpha \to m \mathtt{Bool} \) and an array \( \mathtt{as} : \mathtt{Array} \alpha \), the function `findM?` applies \( p \) to each element of `as` in order and returns the first element for which \( p \) returns `true`, wrapped in `some`. If no such element is found, it returns `none`. The computation stops as soon as a matching element is found.
Array.findIdxM? definition
[Monad m] (p : α → m Bool) (as : Array α) : m (Option Nat)
Full source
/--
Finds the index of the first element of an array for which the monadic predicate `p` returns `true`.
Elements are examined in order from left to right, and the search is terminated when an element that
satisfies `p` is found. If no such element exists in the array, then `none` is returned.
-/
@[inline]
def findIdxM? [Monad m] (p : α → m Bool) (as : Array α) : m (Option Nat) := do
  let mut i := 0
  for a in as do
    if (← p a) then
      return some i
    i := i + 1
  return none
Monadic find index in array
Informal description
Given a monadic predicate \( p : \alpha \to m \text{Bool} \) and an array \( \text{as} : \text{Array } \alpha \), the function `findIdxM?` applies \( p \) to each element of `as` in order (from left to right) and returns the index of the first element for which \( p \) returns `true`, wrapped in `some`. If no such element exists, it returns `none`. The computation stops as soon as a matching element is found.
Array.findSomeRevM? definition
{α : Type u} {β : Type v} {m : Type v → Type w} [Monad m] (f : α → m (Option β)) (as : Array α) : m (Option β)
Full source
/--
Returns the first non-`none` result of applying the monadic function `f` to each element of the
array in reverse order, from right to left. Once a non-`none` result is found, no further elements
are checked. Returns `none` if `f` returns `none` for all elements of the array.

Examples:
```lean example
#eval #[1, 2, 0, -4, 1].findSomeRevM? (m := Except String) fun x => do
  if x = 0 then throw "Zero!"
  else if x < 0 then return (some x)
  else return none
```
```output
Except.ok (some (-4))
```
```lean example
#eval #[1, 2, 0, 4, 1].findSomeRevM? (m := Except String) fun x => do
  if x = 0 then throw "Zero!"
  else if x < 0 then return (some x)
  else return none
```
```output
Except.error "Zero!"
```
-/
@[inline]
def findSomeRevM? {α : Type u} {β : Type v} {m : Type v → Type w} [Monad m] (f : α → m (Option β)) (as : Array α) : m (Option β) :=
  let rec @[specialize] find : (i : Nat) → i ≤ as.size → m (Option β)
    | 0,   _ => pure none
    | i+1, h => do
      have : i < as.size := Nat.lt_of_lt_of_le (Nat.lt_succ_self _) h
      let r ← f as[i]
      match r with
      | some _ => pure r
      | none   =>
        have : i ≤ as.size := Nat.le_of_lt this
        find i this
  find as.size (Nat.le_refl _)
Reverse monadic find with optional result
Informal description
Given a monadic function \( f : \alpha \to m (\text{Option } \beta) \) and an array \( \text{as} : \text{Array } \alpha \), the function `findSomeRevM?` applies \( f \) to each element of `as` in reverse order (from right to left) and returns the first non-`none` result. If all applications of \( f \) return `none`, the result is `none`. The computation stops as soon as a non-`none` result is found.
Array.findRevM? definition
{α : Type} {m : Type → Type w} [Monad m] (p : α → m Bool) (as : Array α) : m (Option α)
Full source
/--
Returns the last element of the array for which the monadic predicate `p` returns `true`, or `none`
if no such element is found. Elements of the array are checked in reverse, from right to left..

The monad `m` is restricted to `Type → Type` to avoid needing to use `ULift Bool` in `p`'s type.

Example:
```lean example
#eval #[7, 5, 8, 1, 2, 6, 5, 8].findRevM? fun i => do
  if i < 5 then
    return true
  if i ≤ 6 then
    IO.println s!"Almost! {i}"
  return false
```
```output
Almost! 5
Almost! 6
```
```output
some 2
```
-/
@[inline]
def findRevM? {α : Type} {m : Type → Type w} [Monad m] (p : α → m Bool) (as : Array α) : m (Option α) :=
  as.findSomeRevM? fun a => return if (← p a) then some a else none
Reverse monadic find in array
Informal description
Given a monadic predicate \( p : \alpha \to m \text{Bool} \) and an array \( \text{as} : \text{Array } \alpha \), the function `findRevM?` applies \( p \) to each element of `as` in reverse order (from right to left) and returns the last element for which \( p \) returns `true`, wrapped in `some`. If no such element exists, it returns `none`. The computation stops as soon as a matching element is found.
Array.instForM instance
: ForM m (Array α) α
Full source
instance : ForM m (Array α) α where
  forM xs f := Array.forM f xs
Monadic Traversal for Arrays
Informal description
For any monad `m` and type `α`, arrays of type `Array α` can be traversed using the `ForM` typeclass, which provides a way to sequentially apply a monadic action to each element of the array.
Array.forM_eq_forM theorem
[Monad m] {f : α → m PUnit} : Array.forM f as 0 as.size = forM as f
Full source
@[simp] theorem forM_eq_forM [Monad m] {f : α → m PUnit} :
    Array.forM f as 0 as.size = forM as f := rfl
Equivalence of Array Monadic Traversal Forms
Informal description
For any monad `m` and any function `f : α → m PUnit`, the monadic traversal of an array `as` using `Array.forM` starting from index `0` up to `as.size` is equal to the monadic traversal of `as` using `forM`.
Array.sum definition
{α} [Add α] [Zero α] : Array α → α
Full source
/--
Computes the sum of the elements of an array.

Examples:
 * `#[a, b, c].sum = a + (b + (c + 0))`
 * `#[1, 2, 5].sum = 8`
-/
@[inline]
def sum {α} [Add α] [Zero α] : Array α → α :=
  foldr (· + ·) 0
Sum of array elements
Informal description
Given a type $\alpha$ equipped with an addition operation and a zero element, the function `Array.sum` computes the sum of all elements in an array of type `Array α` by folding the addition operation over the array elements, starting from the zero element. For example, the sum of the array `#[a, b, c]` is computed as `a + (b + (c + 0))`.
Array.countP definition
{α : Type u} (p : α → Bool) (as : Array α) : Nat
Full source
/--
Counts the number of elements in the array `as` that satisfy the Boolean predicate `p`.

Examples:
 * `#[1, 2, 3, 4, 5].countP (· % 2 == 0) = 2`
 * `#[1, 2, 3, 4, 5].countP (· < 5) = 4`
 * `#[1, 2, 3, 4, 5].countP (· > 5) = 0`
-/
@[inline]
def countP {α : Type u} (p : α → Bool) (as : Array α) : Nat :=
  as.foldr (init := 0) fun a acc => bif p a then acc + 1 else acc
Count elements satisfying a predicate in an array
Informal description
The function `Array.countP` counts the number of elements in an array `as` of type `α` that satisfy the Boolean predicate `p`. It returns a natural number representing the count. Examples: - `#[1, 2, 3, 4, 5].countP (· % 2 == 0)` returns `2` - `#[1, 2, 3, 4, 5].countP (· < 5)` returns `4` - `#[1, 2, 3, 4, 5].countP (· > 5)` returns `0`
Array.count definition
{α : Type u} [BEq α] (a : α) (as : Array α) : Nat
Full source
/--
Counts the number of times an element occurs in an array.

Examples:
 * `#[1, 1, 2, 3, 5].count 1 = 2`
 * `#[1, 1, 2, 3, 5].count 5 = 1`
 * `#[1, 1, 2, 3, 5].count 4 = 0`
-/
@[inline]
def count {α : Type u} [BEq α] (a : α) (as : Array α) : Nat :=
  countP (· == a) as
Count occurrences of an element in an array
Informal description
The function `Array.count` counts the number of occurrences of an element `a` in an array `as` of type `α`, where `α` is equipped with a boolean equality relation. It returns a natural number representing the count. Examples: - `#[1, 1, 2, 3, 5].count 1 = 2` - `#[1, 1, 2, 3, 5].count 5 = 1` - `#[1, 1, 2, 3, 5].count 4 = 0`
Array.map definition
{α : Type u} {β : Type v} (f : α → β) (as : Array α) : Array β
Full source
/--
Applies a function to each element of the array, returning the resulting array of values.

Examples:
* `#[a, b, c].map f = #[f a, f b, f c]`
* `#[].map Nat.succ = #[]`
* `#["one", "two", "three"].map (·.length) = #[3, 3, 5]`
* `#["one", "two", "three"].map (·.reverse) = #["eno", "owt", "eerht"]`
-/
@[inline]
def map {α : Type u} {β : Type v} (f : α → β) (as : Array α) : Array β :=
  Id.run <| as.mapM f
Array mapping function
Informal description
Given a function \( f : \alpha \to \beta \) and an array \( \text{as} : \text{Array} \, \alpha \), the function `Array.map` applies \( f \) to each element of `as` and returns a new array of type \( \text{Array} \, \beta \) containing the results. Examples: - \( \text{map} \, f \, \#[a, b, c] = \#[f \, a, f \, b, f \, c] \) - \( \text{map} \, \text{Nat.succ} \, \#[] = \#[] \) - \( \text{map} \, (\cdot.\text{length}) \, \#[\text{"one"}, \text{"two"}, \text{"three"}] = \#[3, 3, 5] \) - \( \text{map} \, (\cdot.\text{reverse}) \, \#[\text{"one"}, \text{"two"}, \text{"three"}] = \#[\text{"eno"}, \text{"owt"}, \text{"eerht"}] \)
Array.instFunctor instance
: Functor Array
Full source
instance : Functor Array where
  map := map
Array as a Functor
Informal description
The type `Array` is a functor, meaning it can be mapped over with a function while preserving the structure of the array. Specifically, for any function `f : α → β`, applying `Array.map f` to an array `as : Array α` produces a new array `Array β` where each element is the result of applying `f` to the corresponding element of `as`.
Array.mapFinIdx definition
{α : Type u} {β : Type v} (as : Array α) (f : (i : Nat) → α → (h : i < as.size) → β) : Array β
Full source
/--
Applies a function to each element of the array along with the index at which that element is found,
returning the array of results. In addition to the index, the function is also provided with a proof
that the index is valid.

`Array.mapIdx` is a variant that does not provide the function with evidence that the index is
valid.
-/
@[inline]
def mapFinIdx {α : Type u} {β : Type v} (as : Array α) (f : (i : Nat) → α → (h : i < as.size) → β) : Array β :=
  Id.run <| as.mapFinIdxM f
Mapping over array elements with bounded indices
Informal description
Given an array `as` of type `α` and a function `f` that takes an index `i`, an element of the array, and a proof that `i` is within the bounds of `as`, the function `Array.mapFinIdx` applies `f` to each element of `as` from left to right, collecting the results in a new array of type `β`. The function ensures that the index `i` is always valid when accessing elements of `as`.
Array.mapIdx definition
{α : Type u} {β : Type v} (f : Nat → α → β) (as : Array α) : Array β
Full source
/--
Applies a function to each element of the array along with the index at which that element is found,
returning the array of results.

`Array.mapFinIdx` is a variant that additionally provides the function with a proof that the index
is valid.
-/
@[inline]
def mapIdx {α : Type u} {β : Type v} (f : Nat → α → β) (as : Array α) : Array β :=
  Id.run <| as.mapIdxM f
Mapping over array elements with indices
Informal description
Given an array `as` of type `Array α` and a function `f` that takes a natural number index `i` and an element of the array, the function `Array.mapIdx` applies `f` to each element of `as` from left to right, collecting the results in a new array of type `Array β`. The index `i` corresponds to the position of the element in the original array.
Array.zipWithIndex abbrev
Full source
@[deprecated zipIdx (since := "2025-01-21")] abbrev zipWithIndex := @zipIdx
Pair Array Elements with Their Indices
Informal description
Given an array `as` of type `Array α`, the function `Array.zipWithIndex` pairs each element of `as` with its corresponding index, producing a new array of type `Array (α × Nat)` where each element is a pair `(a, i)` with `a` being the original element and `i` its zero-based position in the array.
Array.find? definition
{α : Type u} (p : α → Bool) (as : Array α) : Option α
Full source
/--
Returns the first element of the array for which the predicate `p` returns `true`, or `none` if no
such element is found.

Examples:
* `#[7, 6, 5, 8, 1, 2, 6].find? (· < 5) = some 1`
* `#[7, 6, 5, 8, 1, 2, 6].find? (· < 1) = none`
-/
@[inline]
def find? {α : Type u} (p : α → Bool) (as : Array α) : Option α :=
  Id.run do
    for a in as do
      if p a then
        return a
    return none
Find first element in array satisfying predicate
Informal description
Given a predicate `p : α → Bool` and an array `as : Array α`, the function returns the first element `a` in `as` for which `p a` evaluates to `true`, wrapped in `some`. If no such element exists, it returns `none`. **Examples:** * `#[7, 6, 5, 8, 1, 2, 6].find? (· < 5)` returns `some 1` * `#[7, 6, 5, 8, 1, 2, 6].find? (· < 1)` returns `none`
Array.findSome? definition
{α : Type u} {β : Type v} (f : α → Option β) (as : Array α) : Option β
Full source
/--
Returns the first non-`none` result of applying the function `f` to each element of the
array, in order. Returns `none` if `f` returns `none` for all elements.

Example:
```lean example
#eval #[7, 6, 5, 8, 1, 2, 6].findSome? fun i =>
  if i < 5 then
    some (i * 10)
  else
    none
```
```output
some 10
```
-/
@[inline]
def findSome? {α : Type u} {β : Type v} (f : α → Option β) (as : Array α) : Option β :=
  Id.run <| as.findSomeM? f
Find first non-none result in array
Informal description
Given a function \( f : \alpha \to \text{Option } \beta \) and an array \( \text{as} : \text{Array } \alpha \), the function `findSome?` applies \( f \) to each element of `as` in order and returns the first non-`none` result. If all applications of \( f \) return `none`, the result is `none`. **Example:** For the array `#[7, 6, 5, 8, 1, 2, 6]` and function `fun i => if i < 5 then some (i * 10) else none`, the result is `some 10` (the first element less than 5 multiplied by 10).
Array.findSome! definition
{α : Type u} {β : Type v} [Inhabited β] (f : α → Option β) (xs : Array α) : β
Full source
/--
Returns the first non-`none` result of applying the function `f` to each element of the
array, in order. Panics if `f` returns `none` for all elements.

Example:
```lean example
#eval #[7, 6, 5, 8, 1, 2, 6].findSome? fun i =>
  if i < 5 then
    some (i * 10)
  else
    none
```
```output
some 10
```
-/
@[inline]
def findSome! {α : Type u} {β : Type v} [Inhabited β] (f : α → Option β) (xs : Array α) : β :=
  match xs.findSome? f with
  | some b => b
  | none   => panic! "failed to find element"
Find first non-none result in array (panicking version)
Informal description
Given a function \( f : \alpha \to \text{Option } \beta \) and an array \( \text{xs} : \text{Array } \alpha \), the function `findSome!` applies \( f \) to each element of `xs` in order and returns the first non-`none` result. If all applications of \( f \) return `none`, it raises a panic with the message "failed to find element". This function assumes that the type \( \beta \) has a default value (via the `Inhabited` typeclass). **Example:** For the array `#[7, 6, 5, 8, 1, 2, 6]` and function `fun i => if i < 5 then some (i * 10) else none`, the result is `10` (the first element less than 5 multiplied by 10). If no such element exists, the function panics.
Array.findSomeRev? definition
{α : Type u} {β : Type v} (f : α → Option β) (as : Array α) : Option β
Full source
/--
Returns the first non-`none` result of applying `f` to each element of the array in reverse order,
from right to left. Returns `none` if `f` returns `none` for all elements of the array.

Examples:
 * `#[7, 6, 5, 8, 1, 2, 6].findSome? (fun x => if x < 5 then some (10 * x) else none) = some 10`
 * `#[7, 6, 5, 8, 1, 2, 6].findSome? (fun x => if x < 1 then some (10 * x) else none) = none`
-/
@[inline]
def findSomeRev? {α : Type u} {β : Type v} (f : α → Option β) (as : Array α) : Option β :=
  Id.run <| as.findSomeRevM? f
Reverse find with optional result
Informal description
Given a function \( f : \alpha \to \text{Option } \beta \) and an array \( \text{as} : \text{Array } \alpha \), the function `findSomeRev?` applies \( f \) to each element of `as` in reverse order (from right to left) and returns the first non-`none` result. If all applications of \( f \) return `none`, the result is `none`.
Array.findRev? definition
{α : Type} (p : α → Bool) (as : Array α) : Option α
Full source
/--
Returns the last element of the array for which the predicate `p` returns `true`, or `none` if no
such element is found.

Examples:
* `#[7, 6, 5, 8, 1, 2, 6].findRev? (· < 5) = some 2`
* `#[7, 6, 5, 8, 1, 2, 6].findRev? (· < 1) = none`
-/
@[inline]
def findRev? {α : Type} (p : α → Bool) (as : Array α) : Option α :=
  Id.run <| as.findRevM? p
Reverse find in array
Informal description
Given a predicate \( p : \alpha \to \text{Bool} \) and an array \( \text{as} : \text{Array } \alpha \), the function `findRev?` returns the last element in `as` (when traversed from right to left) that satisfies \( p \), wrapped in `some`. If no such element exists, it returns `none`. **Examples:** * `#[7, 6, 5, 8, 1, 2, 6].findRev? (· < 5)` returns `some 2` (the last element less than 5) * `#[7, 6, 5, 8, 1, 2, 6].findRev? (· < 1)` returns `none` (no element less than 1)
Array.findIdx? definition
{α : Type u} (p : α → Bool) (as : Array α) : Option Nat
Full source
/--
Returns the index of the first element for which `p` returns `true`, or `none` if there is no such
element.

Examples:
* `#[7, 6, 5, 8, 1, 2, 6].findIdx (· < 5) = some 4`
* `#[7, 6, 5, 8, 1, 2, 6].findIdx (· < 1) = none`
-/
@[inline]
def findIdx? {α : Type u} (p : α → Bool) (as : Array α) : Option Nat :=
  let rec @[semireducible] -- This is otherwise irreducible because it uses well-founded recursion.
  loop (j : Nat) :=
    if h : j < as.size then
      if p as[j] then some j else loop (j + 1)
    else none
    decreasing_by simp_wf; decreasing_trivial_pre_omega
  loop 0
First index satisfying a predicate in an array
Informal description
Given a predicate `p : α → Bool` and an array `as : Array α`, the function `findIdx?` returns the index of the first element in `as` that satisfies `p` (i.e., for which `p` returns `true`). If no such element exists, it returns `none`. The search starts from the beginning of the array (index 0) and proceeds sequentially. Examples: - `#[7, 6, 5, 8, 1, 2, 6].findIdx? (· < 5)` returns `some 4` (the index of `1`). - `#[7, 6, 5, 8, 1, 2, 6].findIdx? (· < 1)` returns `none`.
Array.findFinIdx? definition
{α : Type u} (p : α → Bool) (as : Array α) : Option (Fin as.size)
Full source
/--
Returns the index of the first element for which `p` returns `true`, or `none` if there is no such
element. The index is returned as a `Fin`, which guarantees that it is in bounds.

Examples:
* `#[7, 6, 5, 8, 1, 2, 6].findFinIdx? (· < 5) = some (4 : Fin 7)`
* `#[7, 6, 5, 8, 1, 2, 6].findFinIdx? (· < 1) = none`
-/
@[inline]
def findFinIdx? {α : Type u} (p : α → Bool) (as : Array α) : Option (Fin as.size) :=
  let rec @[semireducible] -- This is otherwise irreducible because it uses well-founded recursion.
  loop (j : Nat) :=
    if h : j < as.size then
      if p as[j] then some ⟨j, h⟩ else loop (j + 1)
    else none
    decreasing_by simp_wf; decreasing_trivial_pre_omega
  loop 0
Find first index in array satisfying predicate (with bounds proof)
Informal description
Given an array `as` of type `α` and a predicate `p : α → Bool`, the function returns the first index `i` (as a `Fin as.size` value) where `p(as[i])` is true, or `none` if no such element exists. The `Fin` type ensures the returned index is always within bounds of the array. Examples: * `findFinIdx? (· < 5) #[7, 6, 5, 8, 1, 2, 6]` returns `some 4` (as a `Fin 7` value) * `findFinIdx? (· < 1) #[7, 6, 5, 8, 1, 2, 6]` returns `none`
Array.findIdx?_loop_eq_map_findFinIdx?_loop_val theorem
{xs : Array α} {p : α → Bool} {j} : findIdx?.loop p xs j = (findFinIdx?.loop p xs j).map (·.val)
Full source
theorem findIdx?_loop_eq_map_findFinIdx?_loop_val {xs : Array α} {p : α → Bool} {j} :
    findIdx?.loop p xs j = (findFinIdx?.loop p xs j).map (·.val) := by
  unfold findIdx?.loop
  unfold findFinIdx?.loop
  split <;> rename_i h
  case isTrue =>
    split
    case isTrue => simp
    case isFalse =>
      have : xs.size - (j + 1) < xs.size - j := Nat.sub_succ_lt_self xs.size j h
      rw [findIdx?_loop_eq_map_findFinIdx?_loop_val (j := j + 1)]
  case isFalse => simp
termination_by xs.size - j
Equivalence of Array Search Loops: `findIdx?.loop` and `findFinIdx?.loop` Value Mapping
Informal description
For any array `xs` of type `Array α`, predicate `p : α → Bool`, and natural number index `j`, the result of the loop `findIdx?.loop p xs j` is equal to the value component of the result of the loop `findFinIdx?.loop p xs j` when mapped through the function extracting the underlying natural number from a `Fin` type.
Array.findIdx?_eq_map_findFinIdx?_val theorem
{xs : Array α} {p : α → Bool} : xs.findIdx? p = (xs.findFinIdx? p).map (·.val)
Full source
theorem findIdx?_eq_map_findFinIdx?_val {xs : Array α} {p : α → Bool} :
    xs.findIdx? p = (xs.findFinIdx? p).map (·.val) := by
  simp [findIdx?, findFinIdx?, findIdx?_loop_eq_map_findFinIdx?_loop_val]
Equivalence of Array Search Functions: `findIdx?` and `findFinIdx?` Value Extraction
Informal description
For any array `xs` of type `Array α` and predicate `p : α → Bool`, the result of `findIdx? p xs` is equal to the result of applying the value extraction function to the result of `findFinIdx? p xs` (when mapped through `Option.map`). That is, the natural number index returned by `findIdx?` is the same as the underlying value of the bounded index returned by `findFinIdx?`.
Array.findIdx definition
(p : α → Bool) (as : Array α) : Nat
Full source
/--
Returns the index of the first element for which `p` returns `true`, or the size of the array if
there is no such element.

Examples:
* `#[7, 6, 5, 8, 1, 2, 6].findIdx (· < 5) = 4`
* `#[7, 6, 5, 8, 1, 2, 6].findIdx (· < 1) = 7`
-/
@[inline]
def findIdx (p : α → Bool) (as : Array α) : Nat := (as.findIdx? p).getD as.size
First index satisfying a predicate in an array (with default)
Informal description
Given a predicate `p : α → Bool` and an array `as : Array α`, the function returns the index of the first element in `as` that satisfies `p`. If no such element exists, it returns the size of the array. Examples: - `#[7, 6, 5, 8, 1, 2, 6].findIdx (· < 5)` returns `4` (the index of `1`). - `#[7, 6, 5, 8, 1, 2, 6].findIdx (· < 1)` returns `7` (the size of the array).
Array.idxOfAux definition
[BEq α] (xs : Array α) (v : α) (i : Nat) : Option (Fin xs.size)
Full source
@[semireducible] -- This is otherwise irreducible because it uses well-founded recursion.
def idxOfAux [BEq α] (xs : Array α) (v : α) (i : Nat) : Option (Fin xs.size) :=
  if h : i < xs.size then
    if xs[i] == v then some ⟨i, h⟩
    else idxOfAux xs v (i+1)
  else none
decreasing_by simp_wf; decreasing_trivial_pre_omega
Auxiliary function for finding index of an element in an array
Informal description
The auxiliary function `Array.idxOfAux` takes an array `xs` of type `Array α`, a value `v` of type `α`, and a natural number index `i`. It returns an optional finite index (`Option (Fin xs.size)`) representing the first occurrence of `v` in `xs` starting from index `i`. If `v` is found at index `i`, it returns `some ⟨i, h⟩` where `h` is a proof that `i` is within bounds. If `v` is not found at `i`, it recursively checks the next index `i+1`. If `i` exceeds the array size, it returns `none`.
Array.indexOfAux abbrev
Full source
@[deprecated idxOfAux (since := "2025-01-29")]
abbrev indexOfAux := @idxOfAux
Auxiliary Index Finding Function for Arrays
Informal description
Given an array `xs` of type `Array α` with a boolean equality relation `[BEq α]`, a value `v` of type `α`, and a starting index `i` of type `Nat`, the function `Array.indexOfAux` returns an optional finite index (`Option (Fin xs.size)`) representing the first occurrence of `v` in `xs` starting from index `i`. If found, it returns `some ⟨i, h⟩` where `h` proves `i` is within bounds; otherwise it recursively checks subsequent indices until either finding `v` or reaching the end of the array (returning `none`).
Array.finIdxOf? definition
[BEq α] (xs : Array α) (v : α) : Option (Fin xs.size)
Full source
/--
Returns the index of the first element equal to `a`, or the size of the array if no element is equal
to `a`. The index is returned as a `Fin`, which guarantees that it is in bounds.

Examples:
 * `#["carrot", "potato", "broccoli"].finIdxOf? "carrot" = some 0`
 * `#["carrot", "potato", "broccoli"].finIdxOf? "broccoli" = some 2`
 * `#["carrot", "potato", "broccoli"].finIdxOf? "tomato" = none`
 * `#["carrot", "potato", "broccoli"].finIdxOf? "anything else" = none`
-/
def finIdxOf? [BEq α] (xs : Array α) (v : α) : Option (Fin xs.size) :=
  idxOfAux xs v 0
First occurrence index of an element in an array (as finite index)
Informal description
Given an array `xs` of type `Array α` and an element `v` of type `α`, the function returns the index of the first occurrence of `v` in `xs` as an optional finite index (`Option (Fin xs.size)`). If `v` is found, it returns `some i` where `i` is a valid index within the bounds of `xs`. If `v` is not found, it returns `none`.
Array.indexOf? abbrev
Full source
@[deprecated "`Array.indexOf?` has been deprecated, use `idxOf?` or `finIdxOf?` instead." (since := "2025-01-29")]
abbrev indexOf? := @finIdxOf?
First Occurrence Index of an Element in an Array (as Optional Natural Number)
Informal description
Given an array `xs` of type `Array α` with a boolean equality relation `[BEq α]` and an element `v` of type `α`, the function `Array.indexOf?` returns an optional natural number (`Option Nat`) representing the index of the first occurrence of `v` in `xs`. If `v` is found, it returns `some i` where `i` is the zero-based index of `v` in `xs`; otherwise, it returns `none`.
Array.idxOf definition
[BEq α] (a : α) : Array α → Nat
Full source
/--
Returns the index of the first element equal to `a`, or the size of the array if no element is equal
to `a`.

Examples:
 * `#["carrot", "potato", "broccoli"].idxOf "carrot" = 0`
 * `#["carrot", "potato", "broccoli"].idxOf "broccoli" = 2`
 * `#["carrot", "potato", "broccoli"].idxOf "tomato" = 3`
 * `#["carrot", "potato", "broccoli"].idxOf "anything else" = 3`
-/
def idxOf [BEq α] (a : α) : Array α → Nat := findIdx (· == a)
First occurrence index of an element in an array (with default)
Informal description
Given an array `as` of type `Array α` with a boolean equality relation `BEq α` and an element `a` of type `α`, the function returns the index of the first occurrence of `a` in `as`. If `a` does not appear in `as`, it returns the size of the array. Examples: - `#["carrot", "potato", "broccoli"].idxOf "carrot" = 0` - `#["carrot", "potato", "broccoli"].idxOf "broccoli" = 2` - `#["carrot", "potato", "broccoli"].idxOf "tomato" = 3`
Array.idxOf? definition
[BEq α] (xs : Array α) (v : α) : Option Nat
Full source
/--
Returns the index of the first element equal to `a`, or `none` if no element is equal to `a`.

Examples:
 * `#["carrot", "potato", "broccoli"].idxOf? "carrot" = some 0`
 * `#["carrot", "potato", "broccoli"].idxOf? "broccoli" = some 2`
 * `#["carrot", "potato", "broccoli"].idxOf? "tomato" = none`
 * `#["carrot", "potato", "broccoli"].idxOf? "anything else" = none`
-/
def idxOf? [BEq α] (xs : Array α) (v : α) : Option Nat :=
  (xs.finIdxOf? v).map (·.val)
First occurrence index of an element in an array
Informal description
Given an array `xs` of type `Array α` and an element `v` of type `α`, the function returns the index of the first occurrence of `v` in `xs` as an optional natural number (`Option Nat`). If `v` is found, it returns `some i` where `i` is the zero-based index of the first occurrence. If `v` is not found, it returns `none`.
Array.getIdx? definition
[BEq α] (xs : Array α) (v : α) : Option Nat
Full source
@[deprecated idxOf? (since := "2024-11-20")]
def getIdx? [BEq α] (xs : Array α) (v : α) : Option Nat :=
  xs.findIdx? fun a => a == v
First index of an element in an array
Informal description
Given an array `xs` of type `Array α` with a boolean equality relation `BEq α` and an element `v` of type `α`, the function `getIdx?` returns the index of the first occurrence of `v` in `xs` as an `Option Nat`. If `v` is not found in `xs`, it returns `none`.
Array.contains definition
[BEq α] (as : Array α) (a : α) : Bool
Full source
/--
Checks whether `a` is an element of `as`, using `==` to compare elements.

`Array.elem` is a synonym that takes the element before the array.

Examples:
* `#[1, 4, 2, 3, 3, 7].contains 3 = true`
* `Array.contains #[1, 4, 2, 3, 3, 7] 5 = false`
-/
def contains [BEq α] (as : Array α) (a : α) : Bool :=
  as.any (a == ·)
Array membership check via boolean equality
Informal description
Given an array `as` of type `Array α` with a boolean equality relation `BEq α` and an element `a` of type `α`, the function `contains` checks whether `a` is an element of `as` by comparing elements using the boolean equality operator `==`. It returns `true` if `a` is found in `as` and `false` otherwise.
Array.elem definition
[BEq α] (a : α) (as : Array α) : Bool
Full source
/--
Checks whether `a` is an element of `as`, using `==` to compare elements.

`Array.contains` is a synonym that takes the array before the element.

For verification purposes, `Array.elem` is simplified to `Array.contains`.

Example:
* `Array.elem 3 #[1, 4, 2, 3, 3, 7] = true`
* `Array.elem 5 #[1, 4, 2, 3, 3, 7] = false`
-/
def elem [BEq α] (a : α) (as : Array α) : Bool :=
  as.contains a
Array membership check via boolean equality (infix-style)
Informal description
Given an element $a$ of type $\alpha$ and an array $\mathit{as}$ of type $\text{Array}\,\alpha$ with a boolean equality relation $\text{BEq}\,\alpha$, the function checks whether $a$ is an element of $\mathit{as}$ by comparing elements using the boolean equality operator $==$. It returns $\text{true}$ if $a$ is found in $\mathit{as}$ and $\text{false}$ otherwise. **Examples:** - $\text{Array.elem}\,3\,\#[1, 4, 2, 3, 3, 7] = \text{true}$ - $\text{Array.elem}\,5\,\#[1, 4, 2, 3, 3, 7] = \text{false}$
Array.toListImpl definition
(as : Array α) : List α
Full source
/-- Convert a `Array α` into an `List α`. This is O(n) in the size of the array.  -/
-- This function is exported to C, where it is called by `Array.toList`
-- (the projection) to implement this functionality.
@[export lean_array_to_list_impl]
def toListImpl (as : Array α) : List α :=
  as.foldr List.cons []
Array to list conversion
Informal description
The function converts a dynamic array `as` of type `α` into a linked list of elements of type `α`. This operation has time complexity linear in the size of the array.
Array.toListAppend definition
(as : Array α) (l : List α) : List α
Full source
/--
Prepends an array to a list. The elements of the array are at the beginning of the resulting list.

Equivalent to `as.toList ++ l`.

Examples:
* `#[1, 2].toListAppend [3, 4] = [1, 2, 3, 4]`
* `#[1, 2].toListAppend [] = [1, 2]`
* `#[].toListAppend [3, 4, 5] = [3, 4, 5]`
-/
@[inline]
def toListAppend (as : Array α) (l : List α) : List α :=
  as.foldr List.cons l
Array-to-list prepend function
Informal description
Given an array `as` of type `α` and a list `l` of type `α`, the function returns a new list formed by prepending all elements of `as` to `l`. The resulting list is equivalent to concatenating the list representation of `as` with `l`. Examples: - `#[1, 2].toListAppend [3, 4]` yields `[1, 2, 3, 4]` - `#[1, 2].toListAppend []` yields `[1, 2]` - `#[].toListAppend [3, 4, 5]` yields `[3, 4, 5]`
Array.append definition
(as : Array α) (bs : Array α) : Array α
Full source
/--
Appends two arrays. Normally used via the `++` operator.

Appending arrays takes time proportional to the length of the second array.

Examples:
  * `#[1, 2, 3] ++ #[4, 5] = #[1, 2, 3, 4, 5]`.
  * `#[] ++ #[4, 5] = #[4, 5]`.
  * `#[1, 2, 3] ++ #[] = #[1, 2, 3]`.
-/
protected def append (as : Array α) (bs : Array α) : Array α :=
  bs.foldl (init := as) fun xs v => xs.push v
Array concatenation
Informal description
The function appends two arrays `as` and `bs` of type `Array α`, resulting in a new array where the elements of `bs` follow the elements of `as`. The time complexity is proportional to the length of the second array `bs`. Examples: - $\#[1, 2, 3] \mathbin{++} \#[4, 5] = \#[1, 2, 3, 4, 5]$ - $\#[] \mathbin{++} \#[4, 5] = \#[4, 5]$ - $\#[1, 2, 3] \mathbin{++} \#[] = \#[1, 2, 3]$
Array.instAppend instance
: Append (Array α)
Full source
instance : Append (Array α) := ⟨Array.append⟩
Array Concatenation Operation
Informal description
For any type $\alpha$, the type `Array α` of arrays with elements of type $\alpha$ is equipped with a canonical append operation `++` that concatenates two arrays.
Array.appendList definition
(as : Array α) (bs : List α) : Array α
Full source
/--
Appends an array and a list.

Takes time proportional to the length of the list..

Examples:
  * `#[1, 2, 3].appendList [4, 5] = #[1, 2, 3, 4, 5]`.
  * `#[].appendList [4, 5] = #[4, 5]`.
  * `#[1, 2, 3].appendList [] = #[1, 2, 3]`.
-/
protected def appendList (as : Array α) (bs : List α) : Array α :=
  bs.foldl (init := as) fun xs v => xs.push v
Append list to array
Informal description
The function appends a list $bs$ of type $\text{List } \alpha$ to an array $as$ of type $\text{Array } \alpha$, resulting in a new array where the elements of $bs$ follow the elements of $as$. The time complexity is proportional to the length of the list $bs$. Examples: - $\text{appendList } \#[1, 2, 3] \ [4, 5] = \#[1, 2, 3, 4, 5]$ - $\text{appendList } \#[] \ [4, 5] = \#[4, 5]$ - $\text{appendList } \#[1, 2, 3] \ [] = \#[1, 2, 3]$
Array.instHAppendList instance
: HAppend (Array α) (List α) (Array α)
Full source
instance : HAppend (Array α) (List α) (Array α) := ⟨Array.appendList⟩
Heterogeneous Append for Arrays and Lists
Informal description
For any type $\alpha$, there is a heterogeneous append operation that takes an array of type $\text{Array } \alpha$ and a list of type $\text{List } \alpha$, and returns a new array of type $\text{Array } \alpha$ where the elements of the list are appended to the elements of the array.
Array.flatMapM definition
[Monad m] (f : α → m (Array β)) (as : Array α) : m (Array β)
Full source
/--
Applies a monadic function that returns an array to each element of an array, from left to right.
The resulting arrays are appended.
-/
@[inline]
def flatMapM [Monad m] (f : α → m (Array β)) (as : Array α) : m (Array β) :=
  as.foldlM (init := empty) fun bs a => do return bs ++ (← f a)
Monadic flat map for arrays
Informal description
Given a monad `m`, a function `f : α → m (Array β)`, and an array `as : Array α`, the function `flatMapM` applies `f` to each element of `as` in sequence (from left to right), collecting the resulting arrays and concatenating them into a single array. The operation is performed in the monadic context `m`. More formally, for each element `a` in `as`, `f a` produces an array of type `Array β` in the monad `m`. These arrays are then concatenated together to form the final result, which is an `Array β` in the monad `m`.
Array.concatMapM abbrev
Full source
@[deprecated flatMapM (since := "2024-10-16")] abbrev concatMapM := @flatMapM
Monadic Concatenation Map for Arrays
Informal description
Given a monad `m`, a function `f : α → m (Array β)`, and an array `as : Array α`, the function `concatMapM` applies `f` to each element of `as` in sequence (from left to right), collecting the resulting arrays and concatenating them into a single array. The operation is performed in the monadic context `m`. More formally, for each element `a` in `as`, `f a` produces an array of type `Array β` in the monad `m`. These arrays are then concatenated together to form the final result, which is an `Array β` in the monad `m`.
Array.flatMap definition
(f : α → Array β) (as : Array α) : Array β
Full source
/--
Applies a function that returns an array to each element of an array. The resulting arrays are
appended.

Examples:
* `#[2, 3, 2].flatMap Array.range = #[0, 1, 0, 1, 2, 0, 1]`
* `#[['a', 'b'], ['c', 'd', 'e']].flatMap List.toArray = #['a', 'b', 'c', 'd', 'e']`
-/
@[inline]
def flatMap (f : α → Array β) (as : Array α) : Array β :=
  as.foldl (init := empty) fun bs a => bs ++ f a
Flat map for arrays
Informal description
Given a function $f : \alpha \to \text{Array } \beta$ and an array $\text{as} : \text{Array } \alpha$, the function $\text{flatMap}$ applies $f$ to each element of $\text{as}$ and concatenates all the resulting arrays into a single array. For example: - $\text{flatMap } \text{Array.range } \#[2, 3, 2] = \#[0, 1, 0, 1, 2, 0, 1]$ - $\text{flatMap } \text{List.toArray } \#[['a', 'b'], ['c', 'd', 'e']] = \#['a', 'b', 'c', 'd', 'e']$
Array.concatMap abbrev
Full source
@[deprecated flatMap (since := "2024-10-16")] abbrev concatMap := @flatMap
Concatenation of Mapped Arrays
Informal description
Given a function $f : \alpha \to \text{Array } \beta$ and an array $\text{as} : \text{Array } \alpha$, the function $\text{concatMap}$ applies $f$ to each element of $\text{as}$ and concatenates all the resulting arrays into a single array. For example: - $\text{concatMap } \text{Array.range } \#[2, 3, 2] = \#[0, 1, 0, 1, 2, 0, 1]$ - $\text{concatMap } \text{List.toArray } \#[['a', 'b'], ['c', 'd', 'e']] = \#['a', 'b', 'c', 'd', 'e']$
Array.flatten definition
(xss : Array (Array α)) : Array α
Full source
/--
Appends the contents of array of arrays into a single array. The resulting array contains the same
elements as the nested arrays in the same order.

Examples:
 * `#[#[5], #[4], #[3, 2]].flatten = #[5, 4, 3, 2]`
 * `#[#[0, 1], #[], #[2], #[1, 0, 1]].flatten = #[0, 1, 2, 1, 0, 1]`
 * `(#[] : Array Nat).flatten = #[]`
-/
@[inline] def flatten (xss : Array (Array α)) : Array α :=
  xss.foldl (init := empty) fun acc xs => acc ++ xs
Array flattening (concatenation of nested arrays)
Informal description
Given an array of arrays `xss` of type `Array (Array α)`, the function concatenates all the nested arrays into a single array of type `Array α`, preserving the order of elements. The resulting array is obtained by successively appending each inner array to an initially empty accumulator array. Examples: - `#[#[5], #[4], #[3, 2]].flatten` produces `#[5, 4, 3, 2]` - `#[#[0, 1], #[], #[2], #[1, 0, 1]].flatten` produces `#[0, 1, 2, 1, 0, 1]` - `(#[] : Array Nat).flatten` produces `#[]` (the empty array)
Array.reverse definition
(as : Array α) : Array α
Full source
/--
Reverses an array by repeatedly swapping elements.

The original array is modified in place if there are no other references to it.

Examples:
* `(#[] : Array Nat).reverse = #[]`
* `#[0, 1].reverse = #[1, 0]`
* `#[0, 1, 2].reverse = #[2, 1, 0]`
-/
def reverse (as : Array α) : Array α :=
  if h : as.size ≤ 1 then
    as
  else
    loop as 0 ⟨as.size - 1, Nat.pred_lt (mt (fun h : as.size = 0 => h ▸ by decide) h)⟩
where
  termination {i j : Nat} (h : i < j) : j - 1 - (i + 1) < j - i := by
    rw [Nat.sub_sub, Nat.add_comm]
    exact Nat.lt_of_le_of_lt (Nat.pred_le _) (Nat.sub_succ_lt_self _ _ h)
  loop (as : Array α) (i : Nat) (j : Fin as.size) :=
    if h : i < j then
      have := termination h
      let as := as.swap i j (Nat.lt_trans h j.2)
      have : j-1 < as.size := by rw [size_swap]; exact Nat.lt_of_le_of_lt (Nat.pred_le _) j.2
      loop as (i+1) ⟨j-1, this⟩
    else
      as
Array reversal function
Informal description
The function reverses the elements of an array `as` of type `α` in place when possible (when there are no other references to the array). The reversal is performed by iteratively swapping elements from the start and end of the array moving towards the center. For arrays of size 0 or 1, the array is returned unchanged. Examples: - The reverse of the empty array `#[]` is `#[]` - The reverse of `#[0, 1]` is `#[1, 0]` - The reverse of `#[0, 1, 2]` is `#[2, 1, 0]`
Array.getMax? definition
(as : Array α) (lt : α → α → Bool) : Option α
Full source
/--
Returns the largest element of the array, as determined by the comparison `lt`, or `none` if
the array is empty.

Examples:
* `(#[] : Array Nat).getMax? (· < ·) = none`
* `#["red", "green", "blue"].getMax? (·.length < ·.length) = some "green"`
* `#["red", "green", "blue"].getMax? (· < ·) = some "red"`
-/
@[specialize]
def getMax? (as : Array α) (lt : α → α → Bool) : Option α :=
  if h : 0 < as.size then
    let a0 := as[0]
    some <| as.foldl (init := a0) (start := 1) fun best a =>
      if lt best a then a else best
  else
    none
Maximum element of an array with custom comparison
Informal description
Given an array `as` of elements of type `α` and a comparison function `lt : α → α → Bool`, the function returns the largest element in `as` according to `lt`, or `none` if the array is empty. More precisely: - If `as` is non-empty, it returns `some x` where `x` is an element of `as` such that for all other elements `y` in `as`, `lt x y` is false (i.e., `x` is maximal according to `lt`). - If `as` is empty, it returns `none`.
Array.partition definition
(p : α → Bool) (as : Array α) : Array α × Array α
Full source
/--
Returns a pair of arrays that together contain all the elements of `as`. The first array contains
those elements for which `p` returns `true`, and the second contains those for which `p` returns
`false`.

`as.partition p` is equivalent to `(as.filter p, as.filter (not ∘ p))`, but it is
more efficient since it only has to do one pass over the array.

Examples:
 * `#[1, 2, 5, 2, 7, 7].partition (· > 2) = (#[5, 7, 7], #[1, 2, 2])`
 * `#[1, 2, 5, 2, 7, 7].partition (fun _ => false) = (#[], #[1, 2, 5, 2, 7, 7])`
 * `#[1, 2, 5, 2, 7, 7].partition (fun _ => true) = (#[1, 2, 5, 2, 7, 7], #[])`
-/
@[inline]
def partition (p : α → Bool) (as : Array α) : ArrayArray α × Array α := Id.run do
  let mut bs := #[]
  let mut cs := #[]
  for a in as do
    if p a then
      bs := bs.push a
    else
      cs := cs.push a
  return (bs, cs)
Array partition by predicate
Informal description
Given an array `as` of elements of type `α` and a predicate `p` on `α`, the function returns a pair of arrays `(bs, cs)` where `bs` contains all elements of `as` that satisfy `p` and `cs` contains all elements of `as` that do not satisfy `p`. This is equivalent to `(as.filter p, as.filter (¬ p))` but implemented more efficiently with a single pass through the array. Examples: - For `as = #[1, 2, 5, 2, 7, 7]` and `p = (· > 2)`, the result is `(#[5, 7, 7], #[1, 2, 2])` - For `as = #[1, 2, 5, 2, 7, 7]` and `p = (fun _ => false)`, the result is `(#[], #[1, 2, 5, 2, 7, 7])` - For `as = #[1, 2, 5, 2, 7, 7]` and `p = (fun _ => true)`, the result is `(#[1, 2, 5, 2, 7, 7], #[])`
Array.popWhile definition
(p : α → Bool) (as : Array α) : Array α
Full source
/--
Removes all the elements that satisfy a predicate from the end of an array.

The longest contiguous sequence of elements that all satisfy the predicate is removed.

Examples:
 * `#[0, 1, 2, 3, 4].popWhile (· > 2) = #[0, 1, 2]`
 * `#[3, 2, 3, 4].popWhile (· > 2) = #[3, 2]`
 * `(#[] : Array Nat).popWhile (· > 2) = #[]`
-/
@[semireducible] -- This is otherwise irreducible because it uses well-founded recursion.
def popWhile (p : α → Bool) (as : Array α) : Array α :=
  if h : as.size > 0 then
    if p (as[as.size - 1]'(Nat.sub_lt h (by decide))) then
      popWhile p as.pop
    else
      as
  else
    as
decreasing_by simp_wf; decreasing_trivial_pre_omega
Remove suffix satisfying predicate from array
Informal description
Given a predicate `p` on elements of type `α` and an array `as` of elements of type `α`, the function `Array.popWhile` returns a new array obtained by removing the longest contiguous suffix of elements from `as` that all satisfy `p`. Examples: - For `as = #[0, 1, 2, 3, 4]` and `p = (· > 2)`, the result is `#[0, 1, 2]` - For `as = #[3, 2, 3, 4]` and `p = (· > 2)`, the result is `#[3, 2]` - For `as = #[]` and `p = (· > 2)`, the result is `#[]`
Array.popWhile_empty theorem
{p : α → Bool} : popWhile p #[] = #[]
Full source
@[simp] theorem popWhile_empty {p : α → Bool} :
    popWhile p #[] = #[] := by
  simp [popWhile]
Empty Array Invariance under `popWhile` Operation
Informal description
For any predicate $p$ on elements of type $\alpha$, applying the `popWhile` operation to an empty array results in an empty array, i.e., $\text{popWhile } p \text{ } \#[] = \#[]$.
Array.takeWhile definition
(p : α → Bool) (as : Array α) : Array α
Full source
/--
Returns a new array that contains the longest prefix of elements that satisfy the predicate `p` from
an array.

Examples:
 * `#[0, 1, 2, 3, 2, 1].takeWhile (· < 2) = #[0, 1]`
 * `#[0, 1, 2, 3, 2, 1].takeWhile (· < 20) = #[0, 1, 2, 3, 2, 1]`
 * `#[0, 1, 2, 3, 2, 1].takeWhile (· < 0) = #[]`
-/
def takeWhile (p : α → Bool) (as : Array α) : Array α :=
  let rec @[semireducible] -- This is otherwise irreducible because it uses well-founded recursion.
  go (i : Nat) (acc : Array α) : Array α :=
    if h : i < as.size then
      let a := as[i]
      if p a then
        go (i+1) (acc.push a)
      else
        acc
    else
      acc
    decreasing_by simp_wf; decreasing_trivial_pre_omega
  go 0 #[]
Take while elements satisfy predicate
Informal description
Given a predicate `p` on elements of type `α` and an array `as` of elements of type `α`, the function `Array.takeWhile` returns a new array containing the longest prefix of elements from `as` that satisfy `p`. Examples: - For `as = #[0, 1, 2, 3, 2, 1]` and `p = (· < 2)`, the result is `#[0, 1]` - For `as = #[0, 1, 2, 3, 2, 1]` and `p = (· < 20)`, the result is `as` itself - For `as = #[0, 1, 2, 3, 2, 1]` and `p = (· < 0)`, the result is the empty array `#[]`
Array.size_eraseIdx theorem
{xs : Array α} (i : Nat) (h) : (xs.eraseIdx i h).size = xs.size - 1
Full source
@[simp] theorem size_eraseIdx {xs : Array α} (i : Nat) (h) : (xs.eraseIdx i h).size = xs.size - 1 := by
  induction xs, i, h using Array.eraseIdx.induct with
  | @case1 xs i h h' xs' ih =>
    unfold eraseIdx
    simp +zetaDelta [h', xs', ih]
  | case2 xs i h h' =>
    unfold eraseIdx
    simp [h']
Size Reduction by One After Array Element Removal at Index
Informal description
For any array `xs` of type `Array α` and any index `i` with a proof `h` that `i` is within bounds of `xs`, the size of the array obtained by removing the element at index `i` (`xs.eraseIdx i h`) is equal to the original size of `xs` minus one, i.e., $\text{size}(\text{xs.eraseIdx } i \text{ } h) = \text{size}(\text{xs}) - 1$.
Array.eraseIdxIfInBounds definition
(xs : Array α) (i : Nat) : Array α
Full source
/--
Removes the element at a given index from an array. Does nothing if the index is out of bounds.

This function takes worst-case `O(n)` time because it back-shifts all elements at positions greater
than `i`.

Examples:
* `#["apple", "pear", "orange"].eraseIdxIfInBounds 0 = #["pear", "orange"]`
* `#["apple", "pear", "orange"].eraseIdxIfInBounds 1 = #["apple", "orange"]`
* `#["apple", "pear", "orange"].eraseIdxIfInBounds 2 = #["apple", "pear"]`
* `#["apple", "pear", "orange"].eraseIdxIfInBounds 3 = #["apple", "pear", "orange"]`
* `#["apple", "pear", "orange"].eraseIdxIfInBounds 5 = #["apple", "pear", "orange"]`
-/
def eraseIdxIfInBounds (xs : Array α) (i : Nat) : Array α :=
  if h : i < xs.size then xs.eraseIdx i h else xs
Remove array element at index if in bounds
Informal description
Given an array `xs` of type `α` and a natural number index `i`, this function removes the element at position `i` if `i` is within the bounds of the array (i.e., `i < xs.size`). If `i` is out of bounds, the function returns the original array unchanged. The operation has a worst-case time complexity of `O(n)` due to the need to shift elements after the removed position. Examples: - `#[1, 2, 3].eraseIdxIfInBounds 0 = #[2, 3]` - `#[1, 2, 3].eraseIdxIfInBounds 1 = #[1, 3]` - `#[1, 2, 3].eraseIdxIfInBounds 2 = #[1, 2]` - `#[1, 2, 3].eraseIdxIfInBounds 3 = #[1, 2, 3]` - `#[1, 2, 3].eraseIdxIfInBounds 5 = #[1, 2, 3]`
Array.eraseIdx! definition
(xs : Array α) (i : Nat) : Array α
Full source
/--
Removes the element at a given index from an array. Panics if the index is out of bounds.

This function takes worst-case `O(n)` time because it back-shifts all elements at positions
greater than `i`.
-/
def eraseIdx! (xs : Array α) (i : Nat) : Array α :=
  if h : i < xs.size then xs.eraseIdx i h else panic! "invalid index"
Remove array element at index (panics if out of bounds)
Informal description
The function removes the element at index `i` from the array `xs`. If the index `i` is out of bounds (i.e., `i ≥ xs.size`), the function panics with an "invalid index" error. The operation has a worst-case time complexity of `O(n)` due to the need to shift all elements after the removed position.
Array.erase definition
[BEq α] (as : Array α) (a : α) : Array α
Full source
/--
Removes the first occurrence of a specified element from an array, or does nothing if it is not
present.

This function takes worst-case `O(n)` time because it back-shifts all later elements.

Examples:
* `#[1, 2, 3].erase 2 = #[1, 3]`
* `#[1, 2, 3].erase 5 = #[1, 2, 3]`
* `#[1, 2, 3, 2, 1].erase 2 = #[1, 3, 2, 1]`
* `(#[] : List Nat).erase 2 = #[]`
-/
def erase [BEq α] (as : Array α) (a : α) : Array α :=
  match as.finIdxOf? a with
  | none   => as
  | some i => as.eraseIdx i
Remove first occurrence of an element from an array
Informal description
Given an array `as` of type `α` and an element `a` of type `α`, the function removes the first occurrence of `a` from `as` if it exists, otherwise returns the original array unchanged. The operation has a worst-case time complexity of $O(n)$ due to the need to shift elements after the removed position. Examples: - $\#[1, 2, 3].\text{erase}\ 2 = \#[1, 3]$ - $\#[1, 2, 3].\text{erase}\ 5 = \#[1, 2, 3]$ - $\#[1, 2, 3, 2, 1].\text{erase}\ 2 = \#[1, 3, 2, 1]$ - $\#[] : \text{List Nat}.\text{erase}\ 2 = \#[]$
Array.eraseP definition
(as : Array α) (p : α → Bool) : Array α
Full source
/--
Removes the first element that satisfies the predicate `p`. If no element satisfies `p`, the array
is returned unmodified.

This function takes worst-case `O(n)` time because it back-shifts all later elements.

Examples:
* `#["red", "green", "", "blue"].eraseP (·.isEmpty) = #["red", "green", "blue"]`
* `#["red", "green", "", "blue", ""].eraseP (·.isEmpty) = #["red", "green", "blue", ""]`
* `#["red", "green", "blue"].eraseP (·.length % 2 == 0) = #["red", "green"]`
* `#["red", "green", "blue"].eraseP (fun _ => true) = #["green", "blue"]`
* `(#[] : Array String).eraseP (fun _ => true) = #[]`
-/
def eraseP (as : Array α) (p : α → Bool) : Array α :=
  match as.findFinIdx? p with
  | none   => as
  | some i => as.eraseIdx i
Remove first array element satisfying predicate
Informal description
Given an array `as` of type `α` and a predicate `p : α → Bool`, the function `eraseP` removes the first element in `as` that satisfies `p`. If no such element exists, the array is returned unchanged. The operation has a worst-case time complexity of `O(n)` due to the need to shift elements after the removed position. **Examples:** - `eraseP (·.isEmpty) #["red", "green", "", "blue"] = #["red", "green", "blue"]` - `eraseP (·.isEmpty) #["red", "green", "", "blue", ""] = #["red", "green", "blue", ""]` - `eraseP (·.length % 2 == 0) #["red", "green", "blue"] = #["red", "green"]` - `eraseP (fun _ => true) #["red", "green", "blue"] = #["green", "blue"]` - `eraseP (fun _ => true) (#[] : Array String) = #[]`
Array.insertAt abbrev
Full source
@[deprecated insertIdx (since := "2024-11-20")] abbrev insertAt := @insertIdx
Array Insertion at Index Operation
Informal description
Given an array `as : Array α`, a natural number index `i : Nat`, and an element `a : α`, the operation `Array.insertAt` inserts the element `a` into the array `as` at position `i`. This operation preserves all elements before index `i` and shifts elements at or after `i` one position to the right.
Array.insertIdx! definition
(as : Array α) (i : Nat) (a : α) : Array α
Full source
/--
Inserts an element into an array at the specified index. Panics if the index is greater than the
size of the array.

In other words, the new element is inserted into the array `as` after the first `i` elements of
`as`.

This function takes worst case `O(n)` time because it has to swap the inserted element into place.
`Array.insertIdx` and `Array.insertIdxIfInBounds` are safer alternatives.

Examples:
 * `#["tues", "thur", "sat"].insertIdx! 1 "wed" = #["tues", "wed", "thur", "sat"]`
 * `#["tues", "thur", "sat"].insertIdx! 2 "wed" = #["tues", "thur", "wed", "sat"]`
 * `#["tues", "thur", "sat"].insertIdx! 3 "wed" = #["tues", "thur", "sat", "wed"]`
-/
def insertIdx! (as : Array α) (i : Nat) (a : α) : Array α :=
  if h : i ≤ as.size then
    insertIdx as i a
  else panic! "invalid index"
Array insertion at index (panic on out-of-bounds)
Informal description
The function inserts an element $a$ into an array $as$ at the specified index $i$. If $i$ is greater than the size of the array, the function panics. The insertion places the new element after the first $i$ elements of $as$, resulting in a new array with size increased by one. The operation has a worst-case time complexity of $O(n)$ due to element shifting. **Examples:** - $\text{insertIdx!} \#[\text{"tues"}, \text{"thur"}, \text{"sat"}] \ 1 \ \text{"wed"} = \#[\text{"tues"}, \text{"wed"}, \text{"thur"}, \text{"sat"}]$ - $\text{insertIdx!} \#[\text{"tues"}, \text{"thur"}, \text{"sat"}] \ 2 \ \text{"wed"} = \#[\text{"tues"}, \text{"thur"}, \text{"wed"}, \text{"sat"}]$ - $\text{insertIdx!} \#[\text{"tues"}, \text{"thur"}, \text{"sat"}] \ 3 \ \text{"wed"} = \#[\text{"tues"}, \text{"thur"}, \text{"sat"}, \text{"wed"}]$
Array.insertAt! abbrev
Full source
@[deprecated insertIdx! (since := "2024-11-20")] abbrev insertAt! := @insertIdx!
Array Insertion at Index (Panic on Out-of-Bounds)
Informal description
Given an array `as : Array α`, a natural number index `i : Nat`, and an element `a : α`, the operation `Array.insertAt!` inserts the element `a` into the array `as` at position `i`. If `i` is greater than the size of the array, the function panics. The insertion shifts all elements from index `i` onwards to the right by one position, increasing the array size by one.
Array.insertIdxIfInBounds definition
(as : Array α) (i : Nat) (a : α) : Array α
Full source
/--
Inserts an element into an array at the specified index. The array is returned unmodified if the
index is greater than the size of the array.

In other words, the new element is inserted into the array `as` after the first `i` elements of
`as`.

This function takes worst case `O(n)` time because it has to swap the inserted element into place.

Examples:
 * `#["tues", "thur", "sat"].insertIdxIfInBounds 1 "wed" = #["tues", "wed", "thur", "sat"]`
 * `#["tues", "thur", "sat"].insertIdxIfInBounds 2 "wed" = #["tues", "thur", "wed", "sat"]`
 * `#["tues", "thur", "sat"].insertIdxIfInBounds 3 "wed" = #["tues", "thur", "sat", "wed"]`
 * `#["tues", "thur", "sat"].insertIdxIfInBounds 4 "wed" = #["tues", "thur", "sat"]`
-/
def insertIdxIfInBounds (as : Array α) (i : Nat) (a : α) : Array α :=
  if h : i ≤ as.size then
    insertIdx as i a
  else
    as
Conditional insertion into array at index
Informal description
Given an array `as` of type `α`, a natural number index `i`, and an element `a` of type `α`, the function inserts `a` into `as` at position `i` if `i` is within the bounds of `as` (i.e., `i ≤ as.size`). If `i` is out of bounds, the array is returned unchanged. The insertion shifts all elements from index `i` onwards to the right by one position. Mathematically, if `as = #[a₀, a₁, ..., aₙ₋₁]` and `0 ≤ i ≤ n`, then the result is `#[a₀, ..., aᵢ₋₁, a, aᵢ, ..., aₙ₋₁]`. If `i > n`, the result is `as`.
Array.isPrefixOfAux definition
[BEq α] (as bs : Array α) (hle : as.size ≤ bs.size) (i : Nat) : Bool
Full source
@[semireducible] -- This is otherwise irreducible because it uses well-founded recursion.
def isPrefixOfAux [BEq α] (as bs : Array α) (hle : as.size ≤ bs.size) (i : Nat) : Bool :=
  if h : i < as.size then
    let a := as[i]
    have : i < bs.size := Nat.lt_of_lt_of_le h hle
    let b := bs[i]
    if a == b then
      isPrefixOfAux as bs hle (i+1)
    else
      false
  else
    true
decreasing_by simp_wf; decreasing_trivial_pre_omega
Auxiliary function for checking array prefix
Informal description
The auxiliary function `isPrefixOfAux` checks whether the array `as` is a prefix of the array `bs` starting from index `i`, given that the size of `as` is less than or equal to the size of `bs`. At each step, it compares the elements at position `i` in both arrays. If they are equal, it proceeds to the next index; otherwise, it returns `false`. If the end of `as` is reached without finding any unequal elements, it returns `true`.
Array.isPrefixOf definition
[BEq α] (as bs : Array α) : Bool
Full source
/--
Return `true` if `as` is a prefix of `bs`, or `false` otherwise.

Examples:
 * `#[0, 1, 2].isPrefixOf #[0, 1, 2, 3] = true`
 * `#[0, 1, 2].isPrefixOf #[0, 1, 2] = true`
 * `#[0, 1, 2].isPrefixOf #[0, 1] = false`
 * `#[].isPrefixOf #[0, 1] = true`
-/
def isPrefixOf [BEq α] (as bs : Array α) : Bool :=
  if h : as.size ≤ bs.size then
    isPrefixOfAux as bs h 0
  else
    false
Array prefix check
Informal description
Given two arrays `as` and `bs` of type `α` with a boolean equality relation, the function returns `true` if `as` is a prefix of `bs`, and `false` otherwise. Specifically: - If the size of `as` is less than or equal to the size of `bs`, it checks element-wise equality starting from the first index. - If the size of `as` is greater than the size of `bs`, it immediately returns `false`. Examples: - `#[0, 1, 2].isPrefixOf #[0, 1, 2, 3]` returns `true` - `#[0, 1, 2].isPrefixOf #[0, 1, 2]` returns `true` - `#[0, 1, 2].isPrefixOf #[0, 1]` returns `false` - `#[].isPrefixOf #[0, 1]` returns `true`
Array.zipWithAux definition
(as : Array α) (bs : Array β) (f : α → β → γ) (i : Nat) (cs : Array γ) : Array γ
Full source
@[semireducible, specialize] -- This is otherwise irreducible because it uses well-founded recursion.
def zipWithAux (as : Array α) (bs : Array β) (f : α → β → γ) (i : Nat) (cs : Array γ) : Array γ :=
  if h : i < as.size then
    let a := as[i]
    if h : i < bs.size then
      let b := bs[i]
      zipWithAux as bs f (i+1) <| cs.push <| f a b
    else
      cs
  else
    cs
decreasing_by simp_wf; decreasing_trivial_pre_omega
Auxiliary function for zipping arrays with a function
Informal description
The auxiliary function `Array.zipWithAux` takes two arrays `as : Array α` and `bs : Array β`, a function `f : α → β → γ`, a natural number index `i`, and an accumulator array `cs : Array γ`. It iterates through the arrays starting at index `i`, applying `f` to the corresponding elements of `as` and `bs` (if they exist at that index) and pushing the results into `cs`. The iteration stops when `i` exceeds the size of either array.
Array.zipWith definition
(f : α → β → γ) (as : Array α) (bs : Array β) : Array γ
Full source
/--
Applies a function to the corresponding elements of two arrays, stopping at the end of the shorter
array.

Examples:
* `#[1, 2].zipWith (· + ·) #[5, 6] = #[6, 8]`
* `#[1, 2, 3].zipWith (· + ·) #[5, 6, 10] = #[6, 8, 13]`
* `#[].zipWith (· + ·) #[5, 6] = #[]`
* `#[x₁, x₂, x₃].zipWith f #[y₁, y₂, y₃, y₄] = #[f x₁ y₁, f x₂ y₂, f x₃ y₃]`
-/
@[inline] def zipWith (f : α → β → γ) (as : Array α) (bs : Array β) : Array γ :=
  zipWithAux as bs f 0 #[]
Element-wise function application on arrays
Informal description
Given two arrays `as : Array α` and `bs : Array β`, and a function `f : α → β → γ`, the function `Array.zipWith` returns a new array where each element at index `i` is the result of applying `f` to the `i`-th elements of `as` and `bs`, if both arrays have an element at that index. The resulting array has length equal to the minimum of the lengths of `as` and `bs`.
Array.zip definition
(as : Array α) (bs : Array β) : Array (α × β)
Full source
/--
Combines two arrays into an array of pairs in which the first and second components are the
corresponding elements of each input array. The resulting array is the length of the shorter of the
input arrays.

Examples:
* `#["Mon", "Tue", "Wed"].zip #[1, 2, 3] = #[("Mon", 1), ("Tue", 2), ("Wed", 3)]`
* `#["Mon", "Tue", "Wed"].zip #[1, 2] = #[("Mon", 1), ("Tue", 2)]`
* `#[x₁, x₂, x₃].zip #[y₁, y₂, y₃, y₄] = #[(x₁, y₁), (x₂, y₂), (x₃, y₃)]`
-/
def zip (as : Array α) (bs : Array β) : Array (α × β) :=
  zipWith Prod.mk as bs
Zipping two arrays into an array of pairs
Informal description
Given two arrays `as : Array α` and `bs : Array β`, the function `Array.zip` returns a new array of pairs where each element is formed by combining the corresponding elements from `as` and `bs` at the same index. The resulting array has length equal to the shorter of the two input arrays.
Array.zipWithAll definition
(f : Option α → Option β → γ) (as : Array α) (bs : Array β) : Array γ
Full source
/--
Applies a function to the corresponding elements of both arrays, stopping when there are no more
elements in either array. If one array is shorter than the other, the function is passed `none` for
the missing elements.

Examples:
* `#[1, 6].zipWithAll min #[5, 2] = #[some 1, some 2]`
* `#[1, 2, 3].zipWithAll Prod.mk #[5, 6] = #[(some 1, some 5), (some 2, some 6), (some 3, none)]`
* `#[x₁, x₂].zipWithAll f #[y] = #[f (some x₁) (some y), f (some x₂) none]`
-/
def zipWithAll (f : Option α → Option β → γ) (as : Array α) (bs : Array β) : Array γ :=
  go as bs 0 #[]
where go (as : Array α) (bs : Array β) (i : Nat) (cs : Array γ) :=
  if i < max as.size bs.size then
    let a := as[i]?
    let b := bs[i]?
    go as bs (i+1) (cs.push (f a b))
  else
    cs
  termination_by max as.size bs.size - i
  decreasing_by simp_wf; decreasing_trivial_pre_omega
Element-wise function application on arrays with optional elements
Informal description
Given two arrays `as : Array α` and `bs : Array β`, and a function `f : Option α → Option β → γ`, the function `Array.zipWithAll` applies `f` to corresponding elements of `as` and `bs` up to the maximum length of the two arrays. For indices where one array is shorter than the other, `f` is called with `none` for the missing elements. The resulting array has length equal to the maximum of the lengths of `as` and `bs`.
Array.unzip definition
(as : Array (α × β)) : Array α × Array β
Full source
/--
Separates an array of pairs into two arrays that contain the respective first and second components.

Examples:
* `#[("Monday", 1), ("Tuesday", 2)].unzip = (#["Monday", "Tuesday"], #[1, 2])`
* `#[(x₁, y₁), (x₂, y₂), (x₃, y₃)].unzip = (#[x₁, x₂, x₃], #[y₁, y₂, y₃])`
* `(#[] : Array (Nat × String)).unzip = ((#[], #[]) : List Nat × List String)`
-/
def unzip (as : Array (α × β)) : ArrayArray α × Array β :=
  as.foldl (init := (#[], #[])) fun (as, bs) (a, b) => (as.push a, bs.push b)
Array pair separation (unzip)
Informal description
Given an array `as` of pairs of type `α × β`, the function separates the array into two arrays: the first containing all the first components of the pairs, and the second containing all the second components. The order of elements is preserved in both resulting arrays. **Examples:** * `unzip #[("Monday", 1), ("Tuesday", 2)] = (#["Monday", "Tuesday"], #[1, 2])` * `unzip #[(x₁, y₁), (x₂, y₂), (x₃, y₃)] = (#[x₁, x₂, x₃], #[y₁, y₂, y₃])` * `unzip (#[] : Array (Nat × String)) = (#[], #[])`
Array.split definition
(as : Array α) (p : α → Bool) : Array α × Array α
Full source
@[deprecated partition (since := "2024-11-06")]
def split (as : Array α) (p : α → Bool) : ArrayArray α × Array α :=
  as.foldl (init := (#[], #[])) fun (as, bs) a =>
    if p a then (as.push a, bs) else (as, bs.push a)
Split array by predicate
Informal description
Given an array `as` of type `Array α` and a predicate `p : α → Bool`, the function splits `as` into two arrays: the first containing all elements of `as` that satisfy `p`, and the second containing all elements that do not satisfy `p`. The order of elements in each resulting array is preserved relative to their original order in `as`.
Array.replace definition
[BEq α] (xs : Array α) (a b : α) : Array α
Full source
/--
Replaces the first occurrence of `a` with `b` in an array. The modification is performed in-place
when the reference to the array is unique. Returns the array unmodified when `a` is not present.

Examples:
* `#[1, 2, 3, 2, 1].replace 2 5 = #[1, 5, 3, 2, 1]`
* `#[1, 2, 3, 2, 1].replace 0 5 = #[1, 2, 3, 2, 1]`
* `#[].replace 2 5 = #[]`
-/
def replace [BEq α] (xs : Array α) (a b : α) : Array α :=
  match xs.finIdxOf? a with
  | none => xs
  | some i => xs.set i b
Replace first occurrence in array
Informal description
Given an array `xs` of type `Array α` and elements `a, b` of type `α`, the function replaces the first occurrence of `a` with `b` in `xs` (if `a` is present) and returns the modified array. If `a` is not found in `xs`, the original array is returned unchanged. The modification is performed in-place when the array reference is unique.
Array.instLT instance
[LT α] : LT (Array α)
Full source
instance instLT [LT α] : LT (Array α) := ⟨fun as bs => as.toList < bs.toList⟩
Lexicographic Order on Arrays
Informal description
For any type $\alpha$ with a "less than" relation, the type of arrays over $\alpha$ inherits a lexicographic "less than" relation.
Array.instLE instance
[LT α] : LE (Array α)
Full source
instance instLE [LT α] : LE (Array α) := ⟨fun as bs => as.toList ≤ bs.toList⟩
Lexicographic Order on Arrays
Informal description
For any type $\alpha$ with a "less than" relation, the type of arrays over $\alpha$ inherits a "less than or equal to" relation.
Array.leftpad definition
(n : Nat) (a : α) (xs : Array α) : Array α
Full source
/--
Pads `xs : Array α` on the left with repeated occurrences of `a : α` until it is of size `n`. If `xs`
already has at least `n` elements, it is returned unmodified.

Examples:
 * `#[1, 2, 3].leftpad 5 0 = #[0, 0, 1, 2, 3]`
 * `#["red", "green", "blue"].leftpad 4 "blank" = #["blank", "red", "green", "blue"]`
 * `#["red", "green", "blue"].leftpad 3 "blank" = #["red", "green", "blue"]`
 * `#["red", "green", "blue"].leftpad 1 "blank" = #["red", "green", "blue"]`
-/
def leftpad (n : Nat) (a : α) (xs : Array α) : Array α := replicate (n - xs.size) a ++ xs
Left padding of an array
Informal description
Given a natural number $n$, an element $a$ of type $\alpha$, and an array `xs` of type `Array α`, the function `leftpad` pads `xs` on the left with repeated occurrences of $a$ until the resulting array has size $n$. If `xs` already has at least $n$ elements, it is returned unchanged. **Examples:** - `leftpad 5 0 #[1, 2, 3] = #[0, 0, 1, 2, 3]` - `leftpad 4 "blank" #["red", "green", "blue"] = #["blank", "red", "green", "blue"]` - `leftpad 3 "blank" #["red", "green", "blue"] = #["red", "green", "blue"]` - `leftpad 1 "blank" #["red", "green", "blue"] = #["red", "green", "blue"]`
Array.rightpad definition
(n : Nat) (a : α) (xs : Array α) : Array α
Full source
/--
Pads `xs : Array α` on the right with repeated occurrences of `a : α` until it is of length `n`. If
`l` already has at least `n` elements, it is returned unmodified.

Examples:
 * `#[1, 2, 3].rightpad 5 0 = #[1, 2, 3, 0, 0]`
 * `#["red", "green", "blue"].rightpad 4 "blank" = #["red", "green", "blue", "blank"]`
 * `#["red", "green", "blue"].rightpad 3 "blank" = #["red", "green", "blue"]`
 * `#["red", "green", "blue"].rightpad 1 "blank" = #["red", "green", "blue"]`
-/
def rightpad (n : Nat) (a : α) (xs : Array α) : Array α := xs ++ replicate (n - xs.size) a
Right-padding an array to a given length
Informal description
Given an array `xs` of elements of type `α`, a natural number `n`, and an element `a` of type `α`, the function `rightpad` returns a new array formed by appending `a` to `xs` until the resulting array has length `n`. If `xs` already has length at least `n`, it is returned unchanged. Mathematically, if `xs` has length `l`, the result is `xs` concatenated with `n - l` copies of `a` (when `l ≤ n`), or `xs` itself (when `l ≥ n`).
Array.reduceOption definition
(as : Array (Option α)) : Array α
Full source
/-- Drop `none`s from a Array, and replace each remaining `some a` with `a`. -/
@[inline] def reduceOption (as : Array (Option α)) : Array α :=
  as.filterMap id
Filter and flatten array of optional values
Informal description
Given an array `as` of optional values of type `Option α`, the function returns a new array where all `none` elements are removed and each `some a` is replaced with `a`. For example, applying `reduceOption` to `#[some 1, none, some 2, none, some 3]` results in `#[1, 2, 3]`.
Array.eraseReps definition
{α} [BEq α] (as : Array α) : Array α
Full source
/--
Erases repeated elements, keeping the first element of each run.

`O(|as|)`.

Example:
* `#[1, 3, 2, 2, 2, 3, 3, 5].eraseReps = #[1, 3, 2, 3, 5]`
-/
def eraseReps {α} [BEq α] (as : Array α) : Array α :=
  if h : 0 < as.size then
    let ⟨last, acc⟩ := as.foldl (init := (as[0], #[])) fun ⟨last, acc⟩ a =>
      if a == last then ⟨last, acc⟩ else ⟨a, acc.push last⟩
    acc.push last
  else
    #[]
Remove consecutive duplicates from array
Informal description
Given an array `as` of elements of type `α` with a boolean equality relation `==`, the function `eraseReps` returns a new array where consecutive duplicate elements are removed, keeping only the first occurrence of each run. The operation has time complexity $O(n)$ where $n$ is the length of the array. For example, applying `eraseReps` to `#[1, 3, 2, 2, 2, 3, 3, 5]` results in `#[1, 3, 2, 3, 5]`.
Array.allDiff definition
[BEq α] (as : Array α) : Bool
Full source
/--
Returns `true` if no two elements of `as` are equal according to the `==` operator.

Examples:
 * `#["red", "green", "blue"].allDiff = true`
 * `#["red", "green", "red"].allDiff = false`
 * `(#[] : Array Nat).allDiff = true`
-/
def allDiff [BEq α] (as : Array α) : Bool :=
  allDiffAux as 0
Distinct elements check for arrays
Informal description
Given an array `as` of elements of type `α` equipped with a boolean equality operator `==`, the function returns `true` if all elements in `as` are distinct according to this equality operator, and `false` otherwise. The empty array is considered to have all distinct elements. Examples: - `#["red", "green", "blue"].allDiff` evaluates to `true` - `#["red", "green", "red"].allDiff` evaluates to `false` - `(#[] : Array Nat).allDiff` evaluates to `true`
Array.getEvenElems definition
(as : Array α) : Array α
Full source
/--
Returns a new array that contains the elements at even indices in `as`, starting with the element at
index `0`.

Examples:
* `#[0, 1, 2, 3, 4].getEvenElems = #[0, 2, 4]`
* `#[1, 2, 3, 4].getEvenElems = #[1, 3]`
* `#["red", "green", "blue"].getEvenElems = #["red", "blue"]`
* `(#[] : Array String).getEvenElems = #[]`
-/
@[inline] def getEvenElems (as : Array α) : Array α :=
  (·.2) <| as.foldl (init := (true, Array.empty)) fun (even, acc) a =>
    if even then
      (false, acc.push a)
    else
      (true, acc)
Elements at even indices of an array
Informal description
Given an array `as` of elements of type `α`, the function returns a new array containing the elements at even indices (0, 2, 4, ...) from the original array. The first element (index 0) is always included, followed by every other element at even-numbered positions. Examples: - For `#[0, 1, 2, 3, 4]`, the result is `#[0, 2, 4]` - For `#[1, 2, 3, 4]`, the result is `#[1, 3]` - For `#["red", "green", "blue"]`, the result is `#["red", "blue"]` - For an empty array, the result is an empty array
Array.instToString instance
[ToString α] : ToString (Array α)
Full source
instance [ToString α] : ToString (Array α) where
  toString xs := "#" ++ toString xs.toList
String Representation of Arrays
Informal description
For any type $\alpha$ with a string representation (i.e., an instance of `ToString α`), arrays of elements of type $\alpha$ also have a string representation.