/- Copyright (c) 2014 Parikshit Khanna. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Parikshit Khanna, Jeremy Avigad, Leonardo de Moura, Floris van Doorn, Mario Carneiro, Yury Kudryashov -/ prelude import Init.Data.List.Pairwise import Init.Data.List.Find /-! # Lemmas about `List.eraseP`, `List.erase`, and `List.eraseIdx`. -/ set_option linter.listVariables true -- Enforce naming conventions for `List`/`Array`/`Vector` variables. set_option linter.indexVariables true -- Enforce naming conventions for index variables. namespace List open Nat /-! ### eraseP -/ @[simp] theorem eraseP_nil : [].eraseP p = [] := rfl theorem eraseP_cons {a : α} {l : List α} : (a :: l).eraseP p = bif p a then l else a :: l.eraseP p := rfl @[simp] theorem eraseP_cons_of_pos {l : List α} {p} (h : p a) : (a :: l).eraseP p = l := by simp [eraseP_cons, h] @[simp] theorem eraseP_cons_of_neg {l : List α} {p} (h : ¬p a) : (a :: l).eraseP p = a :: l.eraseP p := by simp [eraseP_cons, h] theorem eraseP_of_forall_not {l : List α} (h : ∀ a, a ∈ l → ¬p a) : l.eraseP p = l := by induction l with | nil => rfl | cons _ _ ih => simp [h _ (.head ..), ih (forall_mem_cons.1 h).2] @[simp] theorem eraseP_eq_nil_iff {xs : List α} {p : α → Bool} : xs.eraseP p = [] ↔ xs = [] ∨ ∃ x, p x ∧ xs = [x] := by induction xs with | nil => simp | cons x xs ih => simp only [eraseP_cons, cond_eq_if] split <;> rename_i h · simp only [reduceCtorEq, cons.injEq, false_or] constructor · rintro rfl simpa · rintro ⟨_, _, rfl, rfl⟩ rfl · simp only [reduceCtorEq, cons.injEq, false_or, false_iff, not_exists, not_and] rintro x h' rfl simp_all @[deprecated eraseP_eq_nil_iff (since := "2025-01-30")] abbrev eraseP_eq_nil := @eraseP_eq_nil_iff theorem eraseP_ne_nil_iff {xs : List α} {p : α → Bool} : xs.eraseP p ≠ [] ↔ xs ≠ [] ∧ ∀ x, p x → xs ≠ [x] := by simp @[deprecated eraseP_ne_nil_iff (since := "2025-01-30")] abbrev eraseP_ne_nil := @eraseP_ne_nil_iff theorem exists_of_eraseP : ∀ {l : List α} {a} (_ : a ∈ l) (_ : p a), ∃ a l₁ l₂, (∀ b ∈ l₁, ¬p b) ∧ p a ∧ l = l₁ ++ a :: l₂ ∧ l.eraseP p = l₁ ++ l₂ | b :: l, _, al, pa => if pb : p b then ⟨b, [], l, forall_mem_nil _, pb, by simp [pb]⟩ else match al with | .head .. => nomatch pb pa | .tail _ al => let ⟨c, l₁, l₂, h₁, h₂, h₃, h₄⟩ := exists_of_eraseP al pa ⟨c, b::l₁, l₂, (forall_mem_cons ..).2 ⟨pb, h₁⟩, h₂, by rw [h₃, cons_append], by simp [pb, h₄]⟩ -- The arguments are explicit here, so this lemma can be used as a case split. theorem exists_or_eq_self_of_eraseP (p) (l : List α) : l.eraseP p = l ∨ ∃ a l₁ l₂, (∀ b ∈ l₁, ¬p b) ∧ p a ∧ l = l₁ ++ a :: l₂ ∧ l.eraseP p = l₁ ++ l₂ := if h : ∃ a ∈ l, p a then let ⟨_, ha, pa⟩ := h .inr (exists_of_eraseP ha pa) else .inl (eraseP_of_forall_not (h ⟨·, ·, ·⟩)) @[simp] theorem length_eraseP_of_mem (al : a ∈ l) (pa : p a) : length (l.eraseP p) = length l - 1 := by let ⟨_, l₁, l₂, _, _, e₁, e₂⟩ := exists_of_eraseP al pa rw [e₂]; simp [length_append, e₁]; rfl theorem length_eraseP {l : List α} : (l.eraseP p).length = if l.any p then l.length - 1 else l.length := by split <;> rename_i h · simp only [any_eq_true] at h obtain ⟨x, m, h⟩ := h simp [length_eraseP_of_mem m h] · simp only [any_eq_true] at h rw [eraseP_of_forall_not] simp_all theorem eraseP_sublist {l : List α} : l.eraseP p <+ l := by match exists_or_eq_self_of_eraseP p l with | .inl h => rw [h]; apply Sublist.refl | .inr ⟨c, l₁, l₂, _, _, h₃, h₄⟩ => rw [h₄, h₃]; simp theorem eraseP_subset {l : List α} : l.eraseP p ⊆ l := eraseP_sublist.subset protected theorem Sublist.eraseP : l₁ <+ l₂ → l₁.eraseP p <+ l₂.eraseP p | .slnil => Sublist.refl _ | .cons a s => by by_cases h : p a · simpa [h] using s.eraseP.trans eraseP_sublist · simpa [h] using s.eraseP.cons _ | .cons₂ a s => by by_cases h : p a · simpa [h] using s · simpa [h] using s.eraseP theorem length_eraseP_le {l : List α} : (l.eraseP p).length ≤ l.length := eraseP_sublist.length_le theorem le_length_eraseP {l : List α} : l.length - 1 ≤ (l.eraseP p).length := by rw [length_eraseP] split <;> simp theorem mem_of_mem_eraseP {l : List α} : a ∈ l.eraseP p → a ∈ l := (eraseP_subset ·) @[simp] theorem mem_eraseP_of_neg {l : List α} (pa : ¬p a) : a ∈ l.eraseP p ↔ a ∈ l := by refine ⟨mem_of_mem_eraseP, fun al => ?_⟩ match exists_or_eq_self_of_eraseP p l with | .inl h => rw [h]; assumption | .inr ⟨c, l₁, l₂, h₁, h₂, h₃, h₄⟩ => rw [h₄]; rw [h₃] at al have : a ≠ c := fun h => (h ▸ pa).elim h₂ simp [this] at al; simp [al] @[simp] theorem eraseP_eq_self_iff {p} {l : List α} : l.eraseP p = l ↔ ∀ a ∈ l, ¬ p a := by rw [← Sublist.length_eq eraseP_sublist, length_eraseP] split <;> rename_i h · simp only [any_eq_true, length_eq_zero_iff] at h constructor · intro; simp_all [Nat.sub_one_eq_self] · intro; obtain ⟨x, m, h⟩ := h; simp_all · simp_all theorem eraseP_map {f : β → α} : ∀ {l : List β}, (map f l).eraseP p = map f (l.eraseP (p ∘ f)) | [] => rfl | b::l => by by_cases h : p (f b) <;> simp [h, eraseP_map, eraseP_cons_of_pos] theorem eraseP_filterMap {f : α → Option β} : ∀ {l : List α}, (filterMap f l).eraseP p = filterMap f (l.eraseP (fun x => match f x with | some y => p y | none => false)) | [] => rfl | a::l => by rw [filterMap_cons, eraseP_cons] split <;> rename_i h · simp [h, eraseP_filterMap] · rename_i b rw [h, eraseP_cons] by_cases w : p b · simp [w] · simp only [w, cond_false] rw [filterMap_cons_some h, eraseP_filterMap] theorem eraseP_filter {f : α → Bool} {l : List α} : (filter f l).eraseP p = filter f (l.eraseP (fun x => p x && f x)) := by rw [← filterMap_eq_filter, eraseP_filterMap] congr ext x simp only [Option.guard] split <;> split at * <;> simp_all theorem eraseP_append_left {a : α} (pa : p a) : ∀ {l₁ : List α} l₂, a ∈ l₁ → (l₁++l₂).eraseP p = l₁.eraseP p ++ l₂ | x :: xs, l₂, h => by by_cases h' : p x <;> simp [h'] rw [eraseP_append_left pa l₂ ((mem_cons.1 h).resolve_left (mt _ h'))] intro | rfl => exact pa theorem eraseP_append_right : ∀ {l₁ : List α} l₂, (∀ b ∈ l₁, ¬p b) → eraseP p (l₁++l₂) = l₁ ++ l₂.eraseP p | [], _, _ => rfl | _ :: _, _, h => by simp [(forall_mem_cons.1 h).1, eraseP_append_right _ (forall_mem_cons.1 h).2] theorem eraseP_append {l₁ l₂ : List α} : (l₁ ++ l₂).eraseP p = if l₁.any p then l₁.eraseP p ++ l₂ else l₁ ++ l₂.eraseP p := by split <;> rename_i h · simp only [any_eq_true] at h obtain ⟨x, m, h⟩ := h rw [eraseP_append_left h _ m] · simp only [any_eq_true] at h rw [eraseP_append_right _] simp_all theorem eraseP_replicate {n : Nat} {a : α} {p : α → Bool} : (replicate n a).eraseP p = if p a then replicate (n - 1) a else replicate n a := by induction n with | zero => simp | succ n ih => simp only [replicate_succ, eraseP_cons] split <;> simp [*] @[simp] theorem eraseP_replicate_of_pos {n : Nat} {a : α} (h : p a) : (replicate n a).eraseP p = replicate (n - 1) a := by cases n <;> simp [replicate_succ, h] @[simp] theorem eraseP_replicate_of_neg {n : Nat} {a : α} (h : ¬p a) : (replicate n a).eraseP p = replicate n a := by rw [eraseP_of_forall_not (by simp_all)] protected theorem IsPrefix.eraseP (h : l₁ <+: l₂) : l₁.eraseP p <+: l₂.eraseP p := by rw [IsPrefix] at h obtain ⟨t, rfl⟩ := h rw [eraseP_append] split · exact prefix_append (eraseP p l₁) t · rw [eraseP_of_forall_not (by simp_all)] exact prefix_append l₁ (eraseP p t) theorem eraseP_eq_iff {p} {l : List α} : l.eraseP p = l' ↔ ((∀ a ∈ l, ¬ p a) ∧ l = l') ∨ ∃ a l₁ l₂, (∀ b ∈ l₁, ¬ p b) ∧ p a ∧ l = l₁ ++ a :: l₂ ∧ l' = l₁ ++ l₂ := by cases exists_or_eq_self_of_eraseP p l with | inl h => constructor · intro h' left exact ⟨eraseP_eq_self_iff.1 h, by simp_all⟩ · rintro (⟨-, rfl⟩ | ⟨a, l₁, l₂, h₁, h₂, rfl, rfl⟩) · assumption · rw [eraseP_append_right _ h₁, eraseP_cons_of_pos h₂] | inr h => obtain ⟨a, l₁, l₂, h₁, h₂, w₁, w₂⟩ := h rw [w₂] subst w₁ constructor · rintro rfl right refine ⟨a, l₁, l₂, ?_⟩ simp_all · rintro (h | h) · simp_all · obtain ⟨a', l₁', l₂', h₁', h₂', h, rfl⟩ := h have p : l₁ = l₁' := by have q : l₁ = takeWhile (fun x => !p x) (l₁ ++ a :: l₂) := by rw [takeWhile_append_of_pos (by simp_all), takeWhile_cons_of_neg (by simp [h₂]), append_nil] have q' : l₁' = takeWhile (fun x => !p x) (l₁' ++ a' :: l₂') := by rw [takeWhile_append_of_pos (by simpa using h₁'), takeWhile_cons_of_neg (by simp [h₂']), append_nil] simp [h] at q rw [q', q] subst p simp_all theorem Pairwise.eraseP (q) : Pairwise p l → Pairwise p (l.eraseP q) := Pairwise.sublist <| eraseP_sublist theorem Nodup.eraseP (p) : Nodup l → Nodup (l.eraseP p) := Pairwise.eraseP p theorem eraseP_comm {l : List α} (h : ∀ a ∈ l, ¬ p a ∨ ¬ q a) : (l.eraseP p).eraseP q = (l.eraseP q).eraseP p := by induction l with | nil => rfl | cons a l ih => simp only [eraseP_cons] by_cases h₁ : p a · by_cases h₂ : q a · simp_all · simp [h₁, h₂, ih (fun b m => h b (mem_cons_of_mem _ m))] · by_cases h₂ : q a · simp [h₁, h₂, ih (fun b m => h b (mem_cons_of_mem _ m))] · simp [h₁, h₂, ih (fun b m => h b (mem_cons_of_mem _ m))] theorem head_eraseP_mem {xs : List α} {p : α → Bool} (h) : (xs.eraseP p).head h ∈ xs := eraseP_sublist.head_mem h theorem getLast_eraseP_mem {xs : List α} {p : α → Bool} (h) : (xs.eraseP p).getLast h ∈ xs := eraseP_sublist.getLast_mem h theorem eraseP_eq_eraseIdx {xs : List α} {p : α → Bool} : xs.eraseP p = match xs.findIdx? p with | none => xs | some i => xs.eraseIdx i := by induction xs with | nil => rfl | cons x xs ih => rw [eraseP_cons, findIdx?_cons] by_cases h : p x · simp [h] · simp only [h] rw [ih] split <;> simp [*] /-! ### erase -/ section erase variable [BEq α] -- The arguments are explicit to allow determining the type, -- and to allow rewriting from right to left. @[simp] theorem erase_cons_head [LawfulBEq α] (a : α) (l : List α) : (a :: l).erase a = l := by simp [erase_cons] @[simp] theorem erase_cons_tail {a b : α} {l : List α} (h : ¬(b == a)) : (b :: l).erase a = b :: l.erase a := by simp only [erase_cons, if_neg h] theorem erase_of_not_mem [LawfulBEq α] {a : α} : ∀ {l : List α}, a ∉ l → l.erase a = l | [], _ => rfl | b :: l, h => by rw [mem_cons, not_or] at h simp only [erase_cons, if_neg, erase_of_not_mem h.2, beq_iff_eq, Ne.symm h.1, not_false_eq_true] -- The arguments are intentionally explicit. theorem erase_eq_eraseP' (a : α) (l : List α) : l.erase a = l.eraseP (· == a) := by induction l · simp · next b t ih => rw [erase_cons, eraseP_cons, ih] if h : b == a then simp [h] else simp [h] -- The arguments are intentionally explicit. theorem erase_eq_eraseP [LawfulBEq α] (a : α) : ∀ (l : List α), l.erase a = l.eraseP (a == ·) | [] => rfl | b :: l => by if h : a = b then simp [h] else simp [h, Ne.symm h, erase_eq_eraseP (l := l)] @[simp] theorem erase_eq_nil_iff [LawfulBEq α] {xs : List α} {a : α} : xs.erase a = [] ↔ xs = [] ∨ xs = [a] := by rw [erase_eq_eraseP] simp @[deprecated erase_eq_nil_iff (since := "2025-01-30")] abbrev erase_eq_nil := @erase_eq_nil_iff theorem erase_ne_nil_iff [LawfulBEq α] {xs : List α} {a : α} : xs.erase a ≠ [] ↔ xs ≠ [] ∧ xs ≠ [a] := by rw [erase_eq_eraseP] simp @[deprecated erase_ne_nil_iff (since := "2025-01-30")] abbrev erase_ne_nil := @erase_ne_nil_iff theorem exists_erase_eq [LawfulBEq α] {a : α} {l : List α} (h : a ∈ l) : ∃ l₁ l₂, a ∉ l₁ ∧ l = l₁ ++ a :: l₂ ∧ l.erase a = l₁ ++ l₂ := by let ⟨_, l₁, l₂, h₁, e, h₂, h₃⟩ := exists_of_eraseP h (beq_self_eq_true _) rw [erase_eq_eraseP]; exact ⟨l₁, l₂, fun h => h₁ _ h (beq_self_eq_true _), eq_of_beq e ▸ h₂, h₃⟩ @[simp] theorem length_erase_of_mem [LawfulBEq α] {a : α} {l : List α} (h : a ∈ l) : length (l.erase a) = length l - 1 := by rw [erase_eq_eraseP]; exact length_eraseP_of_mem h (beq_self_eq_true a) theorem length_erase [LawfulBEq α] {a : α} {l : List α} : length (l.erase a) = if a ∈ l then length l - 1 else length l := by rw [erase_eq_eraseP, length_eraseP] split <;> split <;> simp_all theorem erase_sublist {a : α} {l : List α} : l.erase a <+ l := erase_eq_eraseP' a l ▸ eraseP_sublist .. theorem erase_subset {a : α} {l : List α} : l.erase a ⊆ l := erase_sublist.subset theorem Sublist.erase (a : α) {l₁ l₂ : List α} (h : l₁ <+ l₂) : l₁.erase a <+ l₂.erase a := by simp only [erase_eq_eraseP']; exact h.eraseP theorem IsPrefix.erase (a : α) {l₁ l₂ : List α} (h : l₁ <+: l₂) : l₁.erase a <+: l₂.erase a := by simp only [erase_eq_eraseP']; exact h.eraseP theorem length_erase_le {a : α} {l : List α} : (l.erase a).length ≤ l.length := erase_sublist.length_le theorem le_length_erase [LawfulBEq α] {a : α} {l : List α} : l.length - 1 ≤ (l.erase a).length := by rw [length_erase] split <;> simp theorem mem_of_mem_erase {a b : α} {l : List α} (h : a ∈ l.erase b) : a ∈ l := erase_subset h @[simp] theorem mem_erase_of_ne [LawfulBEq α] {a b : α} {l : List α} (ab : a ≠ b) : a ∈ l.erase b ↔ a ∈ l := erase_eq_eraseP b l ▸ mem_eraseP_of_neg (mt eq_of_beq ab.symm) @[simp] theorem erase_eq_self_iff [LawfulBEq α] {l : List α} : l.erase a = l ↔ a ∉ l := by rw [erase_eq_eraseP', eraseP_eq_self_iff] simp [forall_mem_ne'] theorem erase_filter [LawfulBEq α] {f : α → Bool} {l : List α} : (filter f l).erase a = filter f (l.erase a) := by induction l with | nil => rfl | cons x xs ih => by_cases h : a = x · rw [erase_cons] simp only [h, beq_self_eq_true, ↓reduceIte] rw [filter_cons] split · rw [erase_cons_head] · rw [erase_of_not_mem] simp_all [mem_filter] · rw [erase_cons_tail (by simpa using Ne.symm h), filter_cons, filter_cons] split · rw [erase_cons_tail (by simpa using Ne.symm h), ih] · rw [ih] theorem erase_append_left [LawfulBEq α] {l₁ : List α} (l₂) (h : a ∈ l₁) : (l₁ ++ l₂).erase a = l₁.erase a ++ l₂ := by simp [erase_eq_eraseP]; exact eraseP_append_left (beq_self_eq_true a) l₂ h theorem erase_append_right [LawfulBEq α] {a : α} {l₁ : List α} (l₂ : List α) (h : a ∉ l₁) : (l₁ ++ l₂).erase a = (l₁ ++ l₂.erase a) := by rw [erase_eq_eraseP, erase_eq_eraseP, eraseP_append_right] intros b h' h''; rw [eq_of_beq h''] at h; exact h h' theorem erase_append [LawfulBEq α] {a : α} {l₁ l₂ : List α} : (l₁ ++ l₂).erase a = if a ∈ l₁ then l₁.erase a ++ l₂ else l₁ ++ l₂.erase a := by simp [erase_eq_eraseP, eraseP_append] theorem erase_replicate [LawfulBEq α] {n : Nat} {a b : α} : (replicate n a).erase b = if b == a then replicate (n - 1) a else replicate n a := by rw [erase_eq_eraseP] simp [eraseP_replicate] -- The arguments `a b` are explicit, -- so they can be specified to prevent `simp` repeatedly applying the lemma. theorem erase_comm [LawfulBEq α] (a b : α) {l : List α} : (l.erase a).erase b = (l.erase b).erase a := by if ab : a == b then rw [eq_of_beq ab] else ?_ if ha : a ∈ l then ?_ else simp only [erase_of_not_mem ha, erase_of_not_mem (mt mem_of_mem_erase ha)] if hb : b ∈ l then ?_ else simp only [erase_of_not_mem hb, erase_of_not_mem (mt mem_of_mem_erase hb)] match l, l.erase a, exists_erase_eq ha with | _, _, ⟨l₁, l₂, ha', rfl, rfl⟩ => if h₁ : b ∈ l₁ then rw [erase_append_left _ h₁, erase_append_left _ h₁, erase_append_right _ (mt mem_of_mem_erase ha'), erase_cons_head] else rw [erase_append_right _ h₁, erase_append_right _ h₁, erase_append_right _ ha', erase_cons_tail ab, erase_cons_head] theorem erase_eq_iff [LawfulBEq α] {a : α} {l : List α} : l.erase a = l' ↔ (a ∉ l ∧ l = l') ∨ ∃ l₁ l₂, a ∉ l₁ ∧ l = l₁ ++ a :: l₂ ∧ l' = l₁ ++ l₂ := by rw [erase_eq_eraseP', eraseP_eq_iff] simp only [beq_iff_eq, forall_mem_ne', exists_and_left] constructor · rintro (⟨h, rfl⟩ | ⟨a', l', h, rfl, xs, rfl, rfl⟩) · left; simp_all · right; refine ⟨l', h, xs, by simp⟩ · rintro (⟨h, rfl⟩ | ⟨l₁, h, xs, rfl, rfl⟩) · left; simp_all · right; refine ⟨a, l₁, h, by simp⟩ @[simp] theorem erase_replicate_self [LawfulBEq α] {a : α} : (replicate n a).erase a = replicate (n - 1) a := by cases n <;> simp [replicate_succ] @[simp] theorem erase_replicate_ne [LawfulBEq α] {a b : α} (h : !b == a) : (replicate n a).erase b = replicate n a := by rw [erase_of_not_mem] simp_all theorem Pairwise.erase [LawfulBEq α] {l : List α} (a) : Pairwise p l → Pairwise p (l.erase a) := Pairwise.sublist <| erase_sublist theorem Nodup.erase_eq_filter [LawfulBEq α] {l} (d : Nodup l) (a : α) : l.erase a = l.filter (· != a) := by induction d with | nil => rfl | cons m _n ih => rename_i b l by_cases h : b = a · subst h rw [erase_cons_head, filter_cons_of_neg (by simp)] apply Eq.symm rw [filter_eq_self] simpa [@eq_comm α] using m · simp [beq_false_of_ne h, ih, h] theorem Nodup.mem_erase_iff [LawfulBEq α] {a : α} (d : Nodup l) : a ∈ l.erase b ↔ a ≠ b ∧ a ∈ l := by rw [Nodup.erase_eq_filter d, mem_filter, and_comm, bne_iff_ne] theorem Nodup.not_mem_erase [LawfulBEq α] {a : α} (h : Nodup l) : a ∉ l.erase a := fun H => by simpa using ((Nodup.mem_erase_iff h).mp H).left theorem Nodup.erase [LawfulBEq α] (a : α) : Nodup l → Nodup (l.erase a) := Pairwise.erase a theorem head_erase_mem (xs : List α) (a : α) (h) : (xs.erase a).head h ∈ xs := erase_sublist.head_mem h theorem getLast_erase_mem (xs : List α) (a : α) (h) : (xs.erase a).getLast h ∈ xs := erase_sublist.getLast_mem h theorem erase_eq_eraseIdx (l : List α) (a : α) : l.erase a = match l.idxOf? a with | none => l | some i => l.eraseIdx i := by induction l with | nil => simp | cons x xs ih => rw [erase_cons, idxOf?_cons] split · simp · simp [ih] split <;> simp [*] end erase /-! ### eraseIdx -/ theorem length_eraseIdx {l : List α} {i : Nat} : (l.eraseIdx i).length = if i < l.length then l.length - 1 else l.length := by induction l generalizing i with | nil => simp | cons x l ih => cases i with | zero => simp | succ i => simp only [eraseIdx, length_cons, ih, add_one_lt_add_one_iff, Nat.add_one_sub_one] split · cases l <;> simp_all · rfl theorem length_eraseIdx_of_lt {l : List α} {i} (h : i < length l) : (l.eraseIdx i).length = length l - 1 := by simp [length_eraseIdx, h] @[simp] theorem eraseIdx_zero {l : List α} : eraseIdx l 0 = l.tail := by cases l <;> rfl theorem eraseIdx_eq_take_drop_succ : ∀ (l : List α) (i : Nat), l.eraseIdx i = l.take i ++ l.drop (i + 1) | nil, _ => by simp | a::l, 0 => by simp | a::l, i + 1 => by simp [eraseIdx_eq_take_drop_succ l i] -- See `Init.Data.List.Nat.Erase` for `getElem?_eraseIdx` and `getElem_eraseIdx`. @[simp] theorem eraseIdx_eq_nil_iff {l : List α} {i : Nat} : eraseIdx l i = [] ↔ l = [] ∨ (length l = 1 ∧ i = 0) := by match l, i with | [], _ | a::l, 0 | a::l, i + 1 => simp [Nat.succ_inj'] @[deprecated eraseIdx_eq_nil_iff (since := "2025-01-30")] abbrev eraseIdx_eq_nil := @eraseIdx_eq_nil_iff theorem eraseIdx_ne_nil_iff {l : List α} {i : Nat} : eraseIdx l i ≠ [] ↔ 2 ≤ l.length ∨ (l.length = 1 ∧ i ≠ 0) := by match l with | [] | [a] | a::b::l => simp [Nat.succ_inj'] @[deprecated eraseIdx_ne_nil_iff (since := "2025-01-30")] abbrev eraseIdx_ne_nil := @eraseIdx_ne_nil_iff theorem eraseIdx_sublist : ∀ (l : List α) (k : Nat), eraseIdx l k <+ l | [], _ => by simp | a::l, 0 => by simp | a::l, k + 1 => by simp [eraseIdx_sublist] theorem mem_of_mem_eraseIdx {l : List α} {i : Nat} {a : α} (h : a ∈ l.eraseIdx i) : a ∈ l := (eraseIdx_sublist _ _).mem h theorem eraseIdx_subset {l : List α} {k : Nat} : eraseIdx l k ⊆ l := (eraseIdx_sublist _ _).subset @[simp] theorem eraseIdx_eq_self : ∀ {l : List α} {k : Nat}, eraseIdx l k = l ↔ length l ≤ k | [], _ => by simp | a::l, 0 => by simp [(cons_ne_self _ _).symm] | a::l, k + 1 => by simp [eraseIdx_eq_self] theorem eraseIdx_of_length_le {l : List α} {k : Nat} (h : length l ≤ k) : eraseIdx l k = l := by rw [eraseIdx_eq_self.2 h] -- Arguments are intentionally explicit. theorem length_eraseIdx_le (l : List α) (i : Nat) : length (l.eraseIdx i) ≤ length l := (eraseIdx_sublist _ _).length_le -- Arguments are intentionally explicit. theorem le_length_eraseIdx (l : List α) (i : Nat) : length l - 1 ≤ length (l.eraseIdx i) := by rw [length_eraseIdx] split <;> simp theorem eraseIdx_append_of_lt_length {l : List α} {k : Nat} (hk : k < length l) (l' : List α) : eraseIdx (l ++ l') k = eraseIdx l k ++ l' := by induction l generalizing k with | nil => simp_all | cons x l ih => cases k with | zero => rfl | succ k => simp_all [eraseIdx_cons_succ, Nat.succ_lt_succ_iff] theorem eraseIdx_append_of_length_le {l : List α} {k : Nat} (hk : length l ≤ k) (l' : List α) : eraseIdx (l ++ l') k = l ++ eraseIdx l' (k - length l) := by induction l generalizing k with | nil => simp_all | cons x l ih => cases k with | zero => simp_all | succ k => simp_all [eraseIdx_cons_succ, Nat.succ_sub_succ] theorem eraseIdx_replicate {n : Nat} {a : α} {k : Nat} : (replicate n a).eraseIdx k = if k < n then replicate (n - 1) a else replicate n a := by split <;> rename_i h · rw [eq_replicate_iff, length_eraseIdx_of_lt (by simpa using h)] simp only [length_replicate, true_and] intro b m replace m := mem_of_mem_eraseIdx m simp only [mem_replicate] at m exact m.2 · rw [eraseIdx_of_length_le (by simpa using h)] theorem Pairwise.eraseIdx {l : List α} (k) : Pairwise p l → Pairwise p (l.eraseIdx k) := Pairwise.sublist <| eraseIdx_sublist _ _ theorem Nodup.eraseIdx {l : List α} (k) : Nodup l → Nodup (l.eraseIdx k) := Pairwise.eraseIdx k protected theorem IsPrefix.eraseIdx {l l' : List α} (h : l <+: l') (k : Nat) : eraseIdx l k <+: eraseIdx l' k := by rcases h with ⟨t, rfl⟩ if hkl : k < length l then simp [eraseIdx_append_of_lt_length hkl] else rw [Nat.not_lt] at hkl simp [eraseIdx_append_of_length_le hkl, eraseIdx_of_length_le hkl] -- See also `mem_eraseIdx_iff_getElem` and `mem_eraseIdx_iff_getElem?` in -- `Init/Data/List/Nat/Basic.lean`. theorem erase_eq_eraseIdx_of_idxOf [BEq α] [LawfulBEq α] {l : List α} {a : α} {i : Nat} (w : l.idxOf a = i) : l.erase a = l.eraseIdx i := by subst w rw [erase_eq_iff] by_cases h : a ∈ l · right obtain ⟨as, bs, rfl, h'⟩ := eq_append_cons_of_mem h refine ⟨as, bs, h', by simp, ?_⟩ rw [idxOf_append, if_neg h', idxOf_cons_self, eraseIdx_append_of_length_le] <;> simp · left refine ⟨h, ?_⟩ rw [eq_comm, eraseIdx_eq_self] exact Nat.le_of_eq (idxOf_eq_length h).symm @[deprecated erase_eq_eraseIdx_of_idxOf (since := "2025-01-29")] abbrev erase_eq_eraseIdx_of_indexOf := @erase_eq_eraseIdx_of_idxOf end List