11module
22
3- def parse_music : Unit :=
4- ()
3+ import Std.Data.HashMap.Lemmas
4+
5+ open Std
6+
7+ def parseMusic (musicString : String) : List Nat :=
8+ let noteMap : HashMap String.Slice Nat := .ofList [("o" , 4 ), ("o|" , 2 ), (".|" , 1 )]
9+ (musicString.split ' ' ).filterMap (noteMap[·]?) |>.toList
10+
11+ example : parseMusic "" = [] := by native_decide
12+ example : parseMusic "o o o o" = [4 , 4 , 4 , 4 ] := by native_decide
13+ example : parseMusic ".| .| .| .|" = [1 , 1 , 1 , 1 ] := by native_decide
14+ example : parseMusic "o| o| .| .| o o o o" = [2 , 2 , 1 , 1 , 4 , 4 , 4 , 4 ] := by native_decide
15+ example : parseMusic "o| .| o| .| o o| o o|" = [2 , 1 , 2 , 1 , 4 , 2 , 4 , 2 ] := by native_decide
16+
17+ def noteForValue (value : Nat) (h : value = 1 ∨ value = 2 ∨ value = 4 ) : String :=
18+ match value with
19+ | 0 => False.elim (by simp at h)
20+ | 1 => ".|"
21+ | 2 => "o|"
22+ | 3 => False.elim (by simp at h)
23+ | 4 => "o"
24+ | _ + 5 => False.elim (by simp at h)
25+
26+ def formatMusic (l : List Nat) (hl : ∀ value ∈ l, value = 1 ∨ value = 2 ∨ value = 4 ) : String :=
27+ " " .intercalate ((l.attachWith _ hl).map (fun p => noteForValue p.1 p.2 ))
28+
29+ theorem List.filterMap_beq_congr [BEq α] {l l' : List α} {f : α → Option β}
30+ (hf : ∀ a a', a == a' → f a = f a') (hl : l == l') : l.filterMap f = l'.filterMap f := by
31+ induction l generalizing l' with
32+ | nil => simp_all
33+ | cons h₁ t₁ ih =>
34+ match l' with
35+ | [] => simp_all
36+ | h₂ :: t₂ =>
37+ simp at hl
38+ simp [List.filterMap_cons, ih hl.2 , hf _ _ hl.1 ]
39+
40+ theorem parseMusic_formatMusic {l : List Nat} {hl} : parseMusic (formatMusic l hl) = l := by
41+ rw [parseMusic, formatMusic, Iter.toList_filterMap]
42+ simp +instances only [String.reduceToSingleton]
43+ rw [List.filterMap_beq_congr (fun _ _ => HashMap.getElem?_congr) (String.toList_split_intercalate_beq _)]
44+ · simp only [↓Char.isValue, String.reduceSingleton, List.map_attachWith, List.map_eq_nil_iff,
45+ List.attach_eq_nil_iff, List.map_map]
46+ by_cases hl : l = []
47+ · simp [hl]
48+ · simp [hl]
49+ clear hl
50+ induction l with
51+ | nil => simp
52+ | cons ht tl ih =>
53+ simp only [List.attach_cons]
54+ rw [List.filterMap_cons_some (b := ht)]
55+ · simp only [List.filterMap_map, List.cons.injEq, true_and]
56+ apply ih
57+ refine fun v hv => hl _ (by simp [hv])
58+ · simp
59+ obtain (rfl|rfl|rfl) := hl ht (by simp) <;>
60+ simp [noteForValue, HashMap.ofList_equiv_foldl.getElem_eq, HashMap.getElem_insert]
61+ · simp only [List.map_attachWith, List.mem_map, List.mem_attach, true_and, Subtype.exists,
62+ ↓Char.isValue, forall_exists_index]
63+ rintro _ val hval rfl
64+ obtain (rfl|rfl|rfl) := hl _ hval <;> simp [noteForValue]
565
666/-!
767## Prompt
@@ -25,7 +85,7 @@ def parse_music(music_string: str) -> List[int]:
2585 """
2686```
2787
28- ## Canonical solution
88+ ## Canonical soluton
2989
3090```python3
3191 note_map = {'o': 4, 'o|': 2, '.|': 1}
@@ -50,4 +110,4 @@ def check(candidate):
50110 assert candidate('o| o| .| .| o o o o') == [2, 2, 1, 1, 4, 4, 4, 4]
51111 assert candidate('o| .| o| .| o o| o o|') == [2, 1, 2, 1, 4, 2, 4, 2]
52112```
53- -/
113+ -/
0 commit comments