[{"data":1,"prerenderedAt":2386},["ShallowReactive",2],{"page-\u002Fscala\u002F05-collections":3},{"id":4,"title":5,"body":6,"description":28,"extension":2377,"meta":2378,"navigation":52,"path":2379,"seo":2380,"stem":2384,"__hash__":2385},"content\u002Fscala\u002F05-collections.md","[object Object]",{"type":7,"value":8,"toc":2364},"minimark",[9,14,19,465,469,713,717,1017,1021,2360],[10,11,13],"h1",{"id":12},"_05-collections-persistent-data-structures-fusion","05 — Collections: Persistent Data Structures & Fusion",[15,16,18],"h2",{"id":17},"immutable-collections-persistent-data-structures","Immutable Collections — Persistent Data Structures",[20,21,23],"code-wrapper",{"language":22},"scala",[24,25,29],"pre",{"className":26,"code":27,"language":22,"meta":28,"style":28},"language-scala shiki shiki-themes github-light github-dark","\u002F\u002F Scala's immutable collections are PERSISTENT — structural sharing, not copy-on-write.\n\u002F\u002F \"Updating\" returns a new collection that shares most structure with the old one.\n\n\u002F\u002F List: singly-linked list. Cons (:: ) is O(1). Everything else is O(n).\nval list = List(1, 2, 3)                   \u002F\u002F → 3 cons cells (::), each points to next\n0 :: list                                  \u002F\u002F O(1) — new cons cell pointing to old list head\nlist :+ 4                                  \u002F\u002F O(n) — must traverse entire list to append\nlist(2)                                    \u002F\u002F O(n) — must traverse to index 2\nlist.reverse                               \u002F\u002F O(n) — full traversal + new cons cells\n\n\u002F\u002F Vector: persistent indexed sequence. Backed by RRB-trees (Relaxed Radix Balanced).\n\u002F\u002F O(log₃₂ n) for random access, prepend, append, update — effectively O(1) for \u003C 10⁶ elements.\nval vec = Vector(1, 2, 3, 4, 5)\nvec(0)                                     \u002F\u002F → ~O(1) (log₃₂ 5 = 1 level)\nvec :+ 6                                   \u002F\u002F O(log n) — new tree node sharing most leaves\n0 +: vec                                   \u002F\u002F O(log n) — new tree node\nvec.updated(2, 99)                         \u002F\u002F O(log n) — copy one path, share rest\n\n\u002F\u002F Map: persistent HashTrie or Vector. O(log n) lookup\u002Fupdate.\nval m = Map(\"a\" -> 1, \"b\" -> 2, \"c\" -> 3)  \u002F\u002F → HashTrieMap with hash-based tree\nm(\"a\")                                     \u002F\u002F O(effective O(1)) — hash + trie descent\nm + (\"d\" -> 4)                             \u002F\u002F O(log n) — shared structure with new entry\nm - \"a\"                                    \u002F\u002F O(log n) — new trie without key \"a\"\n\n\u002F\u002F Set: same backing as Map (HashSet \u002F HashTrieSet)\nval s = Set(1, 2, 3)\ns + 4                                      \u002F\u002F O(log n) — shared structure\ns & Set(2, 3, 4)                           \u002F\u002F intersection — O(n) but shares structure\n","",[30,31,32,41,47,54,60,103,118,133,147,156,161,167,173,211,225,239,253,272,277,283,334,347,372,386,391,397,424,437],"code",{"__ignoreMap":28},[33,34,37],"span",{"class":35,"line":36},"line",1,[33,38,40],{"class":39},"sdCPZ","\u002F\u002F Scala's immutable collections are PERSISTENT — structural sharing, not copy-on-write.\n",[33,42,44],{"class":35,"line":43},2,[33,45,46],{"class":39},"\u002F\u002F \"Updating\" returns a new collection that shares most structure with the old one.\n",[33,48,50],{"class":35,"line":49},3,[33,51,53],{"emptyLinePlaceholder":52},true,"\n",[33,55,57],{"class":35,"line":56},4,[33,58,59],{"class":39},"\u002F\u002F List: singly-linked list. Cons (:: ) is O(1). Everything else is O(n).\n",[33,61,63,67,71,74,78,82,86,89,92,94,97,100],{"class":35,"line":62},5,[33,64,66],{"class":65},"svdQ7","val",[33,68,70],{"class":69},"sCrzJ"," list",[33,72,73],{"class":65}," =",[33,75,77],{"class":76},"sIsaT"," List",[33,79,81],{"class":80},"ssxIu","(",[33,83,85],{"class":84},"snvgF","1",[33,87,88],{"class":80},", ",[33,90,91],{"class":84},"2",[33,93,88],{"class":80},[33,95,96],{"class":84},"3",[33,98,99],{"class":80},")                   ",[33,101,102],{"class":39},"\u002F\u002F → 3 cons cells (::), each points to next\n",[33,104,106,109,112,115],{"class":35,"line":105},6,[33,107,108],{"class":84},"0",[33,110,111],{"class":65}," ::",[33,113,114],{"class":80}," list                                  ",[33,116,117],{"class":39},"\u002F\u002F O(1) — new cons cell pointing to old list head\n",[33,119,121,124,127,130],{"class":35,"line":120},7,[33,122,123],{"class":80},"list ",[33,125,126],{"class":65},":+",[33,128,129],{"class":84}," 4",[33,131,132],{"class":39},"                                  \u002F\u002F O(n) — must traverse entire list to append\n",[33,134,136,139,141,144],{"class":35,"line":135},8,[33,137,138],{"class":80},"list(",[33,140,91],{"class":84},[33,142,143],{"class":80},")                                    ",[33,145,146],{"class":39},"\u002F\u002F O(n) — must traverse to index 2\n",[33,148,150,153],{"class":35,"line":149},9,[33,151,152],{"class":80},"list.reverse                               ",[33,154,155],{"class":39},"\u002F\u002F O(n) — full traversal + new cons cells\n",[33,157,159],{"class":35,"line":158},10,[33,160,53],{"emptyLinePlaceholder":52},[33,162,164],{"class":35,"line":163},11,[33,165,166],{"class":39},"\u002F\u002F Vector: persistent indexed sequence. Backed by RRB-trees (Relaxed Radix Balanced).\n",[33,168,170],{"class":35,"line":169},12,[33,171,172],{"class":39},"\u002F\u002F O(log₃₂ n) for random access, prepend, append, update — effectively O(1) for \u003C 10⁶ elements.\n",[33,174,176,178,181,183,186,188,190,192,194,196,198,200,203,205,208],{"class":35,"line":175},13,[33,177,66],{"class":65},[33,179,180],{"class":69}," vec",[33,182,73],{"class":65},[33,184,185],{"class":76}," Vector",[33,187,81],{"class":80},[33,189,85],{"class":84},[33,191,88],{"class":80},[33,193,91],{"class":84},[33,195,88],{"class":80},[33,197,96],{"class":84},[33,199,88],{"class":80},[33,201,202],{"class":84},"4",[33,204,88],{"class":80},[33,206,207],{"class":84},"5",[33,209,210],{"class":80},")\n",[33,212,214,217,219,222],{"class":35,"line":213},14,[33,215,216],{"class":80},"vec(",[33,218,108],{"class":84},[33,220,221],{"class":80},")                                     ",[33,223,224],{"class":39},"\u002F\u002F → ~O(1) (log₃₂ 5 = 1 level)\n",[33,226,228,231,233,236],{"class":35,"line":227},15,[33,229,230],{"class":80},"vec ",[33,232,126],{"class":65},[33,234,235],{"class":84}," 6",[33,237,238],{"class":39},"                                   \u002F\u002F O(log n) — new tree node sharing most leaves\n",[33,240,242,244,247,250],{"class":35,"line":241},16,[33,243,108],{"class":84},[33,245,246],{"class":65}," +:",[33,248,249],{"class":80}," vec                                   ",[33,251,252],{"class":39},"\u002F\u002F O(log n) — new tree node\n",[33,254,256,259,261,263,266,269],{"class":35,"line":255},17,[33,257,258],{"class":80},"vec.updated(",[33,260,91],{"class":84},[33,262,88],{"class":80},[33,264,265],{"class":84},"99",[33,267,268],{"class":80},")                         ",[33,270,271],{"class":39},"\u002F\u002F O(log n) — copy one path, share rest\n",[33,273,275],{"class":35,"line":274},18,[33,276,53],{"emptyLinePlaceholder":52},[33,278,280],{"class":35,"line":279},19,[33,281,282],{"class":39},"\u002F\u002F Map: persistent HashTrie or Vector. O(log n) lookup\u002Fupdate.\n",[33,284,286,288,291,293,296,298,302,305,308,310,313,315,318,320,323,325,328,331],{"class":35,"line":285},20,[33,287,66],{"class":65},[33,289,290],{"class":69}," m",[33,292,73],{"class":65},[33,294,295],{"class":76}," Map",[33,297,81],{"class":80},[33,299,301],{"class":300},"sJ6F3","\"a\"",[33,303,304],{"class":65}," ->",[33,306,307],{"class":84}," 1",[33,309,88],{"class":80},[33,311,312],{"class":300},"\"b\"",[33,314,304],{"class":65},[33,316,317],{"class":84}," 2",[33,319,88],{"class":80},[33,321,322],{"class":300},"\"c\"",[33,324,304],{"class":65},[33,326,327],{"class":84}," 3",[33,329,330],{"class":80},")  ",[33,332,333],{"class":39},"\u002F\u002F → HashTrieMap with hash-based tree\n",[33,335,337,340,342,344],{"class":35,"line":336},21,[33,338,339],{"class":80},"m(",[33,341,301],{"class":300},[33,343,221],{"class":80},[33,345,346],{"class":39},"\u002F\u002F O(effective O(1)) — hash + trie descent\n",[33,348,350,353,356,359,362,364,366,369],{"class":35,"line":349},22,[33,351,352],{"class":80},"m ",[33,354,355],{"class":65},"+",[33,357,358],{"class":80}," (",[33,360,361],{"class":300},"\"d\"",[33,363,304],{"class":65},[33,365,129],{"class":84},[33,367,368],{"class":80},")                             ",[33,370,371],{"class":39},"\u002F\u002F O(log n) — shared structure with new entry\n",[33,373,375,377,380,383],{"class":35,"line":374},23,[33,376,352],{"class":80},[33,378,379],{"class":65},"-",[33,381,382],{"class":300}," \"a\"",[33,384,385],{"class":39},"                                    \u002F\u002F O(log n) — new trie without key \"a\"\n",[33,387,389],{"class":35,"line":388},24,[33,390,53],{"emptyLinePlaceholder":52},[33,392,394],{"class":35,"line":393},25,[33,395,396],{"class":39},"\u002F\u002F Set: same backing as Map (HashSet \u002F HashTrieSet)\n",[33,398,400,402,405,407,410,412,414,416,418,420,422],{"class":35,"line":399},26,[33,401,66],{"class":65},[33,403,404],{"class":69}," s",[33,406,73],{"class":65},[33,408,409],{"class":76}," Set",[33,411,81],{"class":80},[33,413,85],{"class":84},[33,415,88],{"class":80},[33,417,91],{"class":84},[33,419,88],{"class":80},[33,421,96],{"class":84},[33,423,210],{"class":80},[33,425,427,430,432,434],{"class":35,"line":426},27,[33,428,429],{"class":80},"s ",[33,431,355],{"class":65},[33,433,129],{"class":84},[33,435,436],{"class":39},"                                      \u002F\u002F O(log n) — shared structure\n",[33,438,440,442,445,447,449,451,453,455,457,459,462],{"class":35,"line":439},28,[33,441,429],{"class":80},[33,443,444],{"class":65},"&",[33,446,409],{"class":76},[33,448,81],{"class":80},[33,450,91],{"class":84},[33,452,88],{"class":80},[33,454,96],{"class":84},[33,456,88],{"class":80},[33,458,202],{"class":84},[33,460,461],{"class":80},")                           ",[33,463,464],{"class":39},"\u002F\u002F intersection — O(n) but shares structure\n",[15,466,468],{"id":467},"vector-internals-rrb-tree-structure","Vector Internals — RRB-Tree Structure",[20,470,471],{"language":22},[24,472,474],{"className":26,"code":473,"language":22,"meta":28,"style":28},"\u002F\u002F Vector is a 32-ary tree (branching factor = 32).\n\u002F\u002F Depth 1: up to 32 elements. Depth 2: up to 1024. Depth 3: up to 32768.\n\u002F\u002F Each leaf is an Array[AnyRef] of up to 32 elements.\n\n\u002F\u002F Indexed access: vec(i) descends the tree by extracting 5-bit chunks of the index:\n\u002F\u002F   level 2: (i >>> 10) & 0x1F  → which level-1 node\n\u002F\u002F   level 1: (i >>> 5)  & 0x1F  → which leaf node\n\u002F\u002F   level 0:  i         & 0x1F  → which element in leaf\n\n\u002F\u002F Update (updated): copies ONLY the path from root to the modified leaf (~3 nodes for 32K elements).\n\u002F\u002F The other 31 sibling leaves are shared. This is \"path copying\" — O(log₃₂ n) new nodes.\n\n\u002F\u002F ❌ ANTI-PATTERN: building a Vector with :+ in a loop — O(n log n) total\nvar v = Vector.empty[Int]\nfor i \u003C- 1 to 10000 do v = v :+ i          \u002F\u002F each :+ is O(log n), total O(n log n) + allocations\n\n\u002F\u002F ✅ CORRECT: build with List cons or Array, then convert\nval built = (1 to 10000).foldLeft(Vector.empty[Int])((acc, i) => acc :+ i)  \u002F\u002F still O(n log n)\n\u002F\u002F Better: use a builder (mutable, then freeze)\nval builder = Vector.newBuilder[Int]\nfor i \u003C- 1 to 10000 do builder += i\nval fast = builder.result()                \u002F\u002F O(n) — single tree construction\n",[30,475,476,481,486,491,495,500,505,510,515,519,524,529,533,538,559,597,601,606,650,655,673,698],{"__ignoreMap":28},[33,477,478],{"class":35,"line":36},[33,479,480],{"class":39},"\u002F\u002F Vector is a 32-ary tree (branching factor = 32).\n",[33,482,483],{"class":35,"line":43},[33,484,485],{"class":39},"\u002F\u002F Depth 1: up to 32 elements. Depth 2: up to 1024. Depth 3: up to 32768.\n",[33,487,488],{"class":35,"line":49},[33,489,490],{"class":39},"\u002F\u002F Each leaf is an Array[AnyRef] of up to 32 elements.\n",[33,492,493],{"class":35,"line":56},[33,494,53],{"emptyLinePlaceholder":52},[33,496,497],{"class":35,"line":62},[33,498,499],{"class":39},"\u002F\u002F Indexed access: vec(i) descends the tree by extracting 5-bit chunks of the index:\n",[33,501,502],{"class":35,"line":105},[33,503,504],{"class":39},"\u002F\u002F   level 2: (i >>> 10) & 0x1F  → which level-1 node\n",[33,506,507],{"class":35,"line":120},[33,508,509],{"class":39},"\u002F\u002F   level 1: (i >>> 5)  & 0x1F  → which leaf node\n",[33,511,512],{"class":35,"line":135},[33,513,514],{"class":39},"\u002F\u002F   level 0:  i         & 0x1F  → which element in leaf\n",[33,516,517],{"class":35,"line":149},[33,518,53],{"emptyLinePlaceholder":52},[33,520,521],{"class":35,"line":158},[33,522,523],{"class":39},"\u002F\u002F Update (updated): copies ONLY the path from root to the modified leaf (~3 nodes for 32K elements).\n",[33,525,526],{"class":35,"line":163},[33,527,528],{"class":39},"\u002F\u002F The other 31 sibling leaves are shared. This is \"path copying\" — O(log₃₂ n) new nodes.\n",[33,530,531],{"class":35,"line":169},[33,532,53],{"emptyLinePlaceholder":52},[33,534,535],{"class":35,"line":175},[33,536,537],{"class":39},"\u002F\u002F ❌ ANTI-PATTERN: building a Vector with :+ in a loop — O(n log n) total\n",[33,539,540,543,546,548,550,553,556],{"class":35,"line":213},[33,541,542],{"class":65},"var",[33,544,545],{"class":69}," v",[33,547,73],{"class":65},[33,549,185],{"class":76},[33,551,552],{"class":80},".empty[",[33,554,555],{"class":76},"Int",[33,557,558],{"class":80},"]\n",[33,560,561,564,567,570,572,575,578,581,584,587,589,591,594],{"class":35,"line":227},[33,562,563],{"class":65},"for",[33,565,566],{"class":80}," i ",[33,568,569],{"class":65},"\u003C-",[33,571,307],{"class":84},[33,573,574],{"class":80}," to ",[33,576,577],{"class":84},"10000",[33,579,580],{"class":65}," do",[33,582,583],{"class":80}," v ",[33,585,586],{"class":65},"=",[33,588,583],{"class":80},[33,590,126],{"class":65},[33,592,593],{"class":80}," i          ",[33,595,596],{"class":39},"\u002F\u002F each :+ is O(log n), total O(n log n) + allocations\n",[33,598,599],{"class":35,"line":241},[33,600,53],{"emptyLinePlaceholder":52},[33,602,603],{"class":35,"line":255},[33,604,605],{"class":39},"\u002F\u002F ✅ CORRECT: build with List cons or Array, then convert\n",[33,607,608,610,613,615,617,619,621,623,626,629,631,633,636,639,642,644,647],{"class":35,"line":274},[33,609,66],{"class":65},[33,611,612],{"class":69}," built",[33,614,73],{"class":65},[33,616,358],{"class":80},[33,618,85],{"class":84},[33,620,574],{"class":80},[33,622,577],{"class":84},[33,624,625],{"class":80},").foldLeft(",[33,627,628],{"class":76},"Vector",[33,630,552],{"class":80},[33,632,555],{"class":76},[33,634,635],{"class":80},"])((acc, i) ",[33,637,638],{"class":65},"=>",[33,640,641],{"class":80}," acc ",[33,643,126],{"class":65},[33,645,646],{"class":80}," i)  ",[33,648,649],{"class":39},"\u002F\u002F still O(n log n)\n",[33,651,652],{"class":35,"line":279},[33,653,654],{"class":39},"\u002F\u002F Better: use a builder (mutable, then freeze)\n",[33,656,657,659,662,664,666,669,671],{"class":35,"line":285},[33,658,66],{"class":65},[33,660,661],{"class":69}," builder",[33,663,73],{"class":65},[33,665,185],{"class":76},[33,667,668],{"class":80},".newBuilder[",[33,670,555],{"class":76},[33,672,558],{"class":80},[33,674,675,677,679,681,683,685,687,689,692,695],{"class":35,"line":336},[33,676,563],{"class":65},[33,678,566],{"class":80},[33,680,569],{"class":65},[33,682,307],{"class":84},[33,684,574],{"class":80},[33,686,577],{"class":84},[33,688,580],{"class":65},[33,690,691],{"class":80}," builder ",[33,693,694],{"class":65},"+=",[33,696,697],{"class":80}," i\n",[33,699,700,702,705,707,710],{"class":35,"line":349},[33,701,66],{"class":65},[33,703,704],{"class":69}," fast",[33,706,73],{"class":65},[33,708,709],{"class":80}," builder.result()                ",[33,711,712],{"class":39},"\u002F\u002F O(n) — single tree construction\n",[15,714,716],{"id":715},"lazy-views-fusion-avoid-intermediate-collections","Lazy Views & Fusion — Avoid Intermediate Collections",[20,718,719],{"language":22},[24,720,722],{"className":26,"code":721,"language":22,"meta":28,"style":28},"\u002F\u002F ❌ ANTI-PATTERN: chained strict ops create N intermediate collections\nval result = (1 to 1000000).toList\n  .map(_ * 2)                              \u002F\u002F allocates List of 1M\n  .filter(_ > 1000)                        \u002F\u002F allocates List of ~999K\n  .map(_ \u002F 2)                              \u002F\u002F allocates List of ~999K\n  .take(10)                                \u002F\u002F allocates List of 10\n\u002F\u002F Total: 3 full list traversals + 3 intermediate collections of ~1M elements each\n\n\u002F\u002F ✅ CORRECT: .view makes operations lazy — single pass, no intermediates\nval result2 = (1 to 1000000).view\n  .map(_ * 2)                              \u002F\u002F lazy — no allocation yet\n  .filter(_ > 1000)                        \u002F\u002F lazy — no allocation yet\n  .map(_ \u002F 2)                              \u002F\u002F lazy — no allocation yet\n  .take(10)                                \u002F\u002F lazy — stops after 10 elements found\n  .to(Vector)                              \u002F\u002F force: evaluates ONLY until 10 elements found\n\u002F\u002F Total: ~20 elements evaluated (10 passed filter × 2 for filter ratio), 1 final Vector\n\n\u002F\u002F .view returns a SeqView — a lazy wrapper that defers all transformations.\n\u002F\u002F .to(Vector) \u002F .toList \u002F .size forces evaluation.\n\u002F\u002F .foreach \u002F .foldLeft also forces evaluation.\n\n\u002F\u002F ⚠️ Views are NOT memoized — re-forcing re-evaluates.\nval view = (1 to 10).view.map { x => println(s\"eval $x\"); x * 2 }\nview.take(3).to(Vector)                    \u002F\u002F prints eval 1, eval 2, eval 3\nview.take(3).to(Vector)                    \u002F\u002F prints eval 1, eval 2, eval 3 AGAIN\n",[30,723,724,729,750,766,783,796,810,815,819,824,844,857,869,881,892,904,909,913,918,923,928,932,937,984,1002],{"__ignoreMap":28},[33,725,726],{"class":35,"line":36},[33,727,728],{"class":39},"\u002F\u002F ❌ ANTI-PATTERN: chained strict ops create N intermediate collections\n",[33,730,731,733,736,738,740,742,744,747],{"class":35,"line":43},[33,732,66],{"class":65},[33,734,735],{"class":69}," result",[33,737,73],{"class":65},[33,739,358],{"class":80},[33,741,85],{"class":84},[33,743,574],{"class":80},[33,745,746],{"class":84},"1000000",[33,748,749],{"class":80},").toList\n",[33,751,752,755,758,760,763],{"class":35,"line":49},[33,753,754],{"class":80},"  .map(_ ",[33,756,757],{"class":65},"*",[33,759,317],{"class":84},[33,761,762],{"class":80},")                              ",[33,764,765],{"class":39},"\u002F\u002F allocates List of 1M\n",[33,767,768,771,774,777,780],{"class":35,"line":56},[33,769,770],{"class":80},"  .filter(_ ",[33,772,773],{"class":65},">",[33,775,776],{"class":84}," 1000",[33,778,779],{"class":80},")                        ",[33,781,782],{"class":39},"\u002F\u002F allocates List of ~999K\n",[33,784,785,787,790,792,794],{"class":35,"line":62},[33,786,754],{"class":80},[33,788,789],{"class":65},"\u002F",[33,791,317],{"class":84},[33,793,762],{"class":80},[33,795,782],{"class":39},[33,797,798,801,804,807],{"class":35,"line":105},[33,799,800],{"class":80},"  .take(",[33,802,803],{"class":84},"10",[33,805,806],{"class":80},")                                ",[33,808,809],{"class":39},"\u002F\u002F allocates List of 10\n",[33,811,812],{"class":35,"line":120},[33,813,814],{"class":39},"\u002F\u002F Total: 3 full list traversals + 3 intermediate collections of ~1M elements each\n",[33,816,817],{"class":35,"line":135},[33,818,53],{"emptyLinePlaceholder":52},[33,820,821],{"class":35,"line":149},[33,822,823],{"class":39},"\u002F\u002F ✅ CORRECT: .view makes operations lazy — single pass, no intermediates\n",[33,825,826,828,831,833,835,837,839,841],{"class":35,"line":158},[33,827,66],{"class":65},[33,829,830],{"class":69}," result2",[33,832,73],{"class":65},[33,834,358],{"class":80},[33,836,85],{"class":84},[33,838,574],{"class":80},[33,840,746],{"class":84},[33,842,843],{"class":80},").view\n",[33,845,846,848,850,852,854],{"class":35,"line":163},[33,847,754],{"class":80},[33,849,757],{"class":65},[33,851,317],{"class":84},[33,853,762],{"class":80},[33,855,856],{"class":39},"\u002F\u002F lazy — no allocation yet\n",[33,858,859,861,863,865,867],{"class":35,"line":169},[33,860,770],{"class":80},[33,862,773],{"class":65},[33,864,776],{"class":84},[33,866,779],{"class":80},[33,868,856],{"class":39},[33,870,871,873,875,877,879],{"class":35,"line":175},[33,872,754],{"class":80},[33,874,789],{"class":65},[33,876,317],{"class":84},[33,878,762],{"class":80},[33,880,856],{"class":39},[33,882,883,885,887,889],{"class":35,"line":213},[33,884,800],{"class":80},[33,886,803],{"class":84},[33,888,806],{"class":80},[33,890,891],{"class":39},"\u002F\u002F lazy — stops after 10 elements found\n",[33,893,894,897,899,901],{"class":35,"line":227},[33,895,896],{"class":80},"  .to(",[33,898,628],{"class":76},[33,900,762],{"class":80},[33,902,903],{"class":39},"\u002F\u002F force: evaluates ONLY until 10 elements found\n",[33,905,906],{"class":35,"line":241},[33,907,908],{"class":39},"\u002F\u002F Total: ~20 elements evaluated (10 passed filter × 2 for filter ratio), 1 final Vector\n",[33,910,911],{"class":35,"line":255},[33,912,53],{"emptyLinePlaceholder":52},[33,914,915],{"class":35,"line":274},[33,916,917],{"class":39},"\u002F\u002F .view returns a SeqView — a lazy wrapper that defers all transformations.\n",[33,919,920],{"class":35,"line":279},[33,921,922],{"class":39},"\u002F\u002F .to(Vector) \u002F .toList \u002F .size forces evaluation.\n",[33,924,925],{"class":35,"line":285},[33,926,927],{"class":39},"\u002F\u002F .foreach \u002F .foldLeft also forces evaluation.\n",[33,929,930],{"class":35,"line":336},[33,931,53],{"emptyLinePlaceholder":52},[33,933,934],{"class":35,"line":349},[33,935,936],{"class":39},"\u002F\u002F ⚠️ Views are NOT memoized — re-forcing re-evaluates.\n",[33,938,939,941,944,946,948,950,952,954,957,959,962,965,968,971,974,977,979,981],{"class":35,"line":374},[33,940,66],{"class":65},[33,942,943],{"class":69}," view",[33,945,73],{"class":65},[33,947,358],{"class":80},[33,949,85],{"class":84},[33,951,574],{"class":80},[33,953,803],{"class":84},[33,955,956],{"class":80},").view.map { x ",[33,958,638],{"class":65},[33,960,961],{"class":80}," println(",[33,963,964],{"class":65},"s",[33,966,967],{"class":300},"\"eval ",[33,969,970],{"class":80},"$x",[33,972,973],{"class":300},"\"",[33,975,976],{"class":80},"); x ",[33,978,757],{"class":65},[33,980,317],{"class":84},[33,982,983],{"class":80}," }\n",[33,985,986,989,991,994,996,999],{"class":35,"line":388},[33,987,988],{"class":80},"view.take(",[33,990,96],{"class":84},[33,992,993],{"class":80},").to(",[33,995,628],{"class":76},[33,997,998],{"class":80},")                    ",[33,1000,1001],{"class":39},"\u002F\u002F prints eval 1, eval 2, eval 3\n",[33,1003,1004,1006,1008,1010,1012,1014],{"class":35,"line":393},[33,1005,988],{"class":80},[33,1007,96],{"class":84},[33,1009,993],{"class":80},[33,1011,628],{"class":76},[33,1013,998],{"class":80},[33,1015,1016],{"class":39},"\u002F\u002F prints eval 1, eval 2, eval 3 AGAIN\n",[15,1018,1020],{"id":1019},"collection-performance-cheat-sheet","Collection Performance Cheat Sheet",[20,1022,1024,1031,1035,1251,1255,1532,1536,1840,1844,2059,2063,2078,2124,2132,2141,2170,2174,2192,2212,2239,2248,2267,2271,2282],{"language":1023},"text",[24,1025,1029],{"className":1026,"code":1028,"language":1023,"meta":28},[1027],"language-text","Collection       Access    Head\u002FTail   Append   Prepend   Update    Memory\n─────────────────────────────────────────────────────────────────────────────\nList             O(n)      O(1)        O(n)     O(1)      O(n)      1 cons\u002Felem\nVector           O(log₃₂n) O(log n)   O(log n) O(log n)  O(log n)  tree nodes\nArrayBuffer(m)   O(1)      O(1)        O(1) am  O(n)      O(1)      contiguous\nArray(m)         O(1)      O(1)        —        —         O(1)      primitive\nHashMap          O(log n)  —           O(log n) —         O(log n)  trie nodes\nHashSet          O(log n)  —           O(log n) —         O(log n)  trie nodes\nListMap          O(n)      —           O(1)     —         O(n)      cons per entry\n",[30,1030,1028],{"__ignoreMap":28},[15,1032,1034],{"id":1033},"real-world-streaming-log-aggregation","Real-World: Streaming Log Aggregation",[20,1036,1037],{"language":22},[24,1038,1040],{"className":26,"code":1039,"language":22,"meta":28,"style":28},"\u002F\u002F Production pattern: process multi-GB log files without loading into memory\nimport scala.util.Using\nimport scala.io.Source\n\ndef aggregateErrors(path: String): Map[String, Int] =\n  Using.resource(Source.fromFile(path)) { src =>\n    src.getLines()                         \u002F\u002F Iterator[String] — lazy, line-by-line\n      .filter(_.contains(\"ERROR\"))         \u002F\u002F lazy — Iterator.filter\n      .map(line => line.substring(0, 20))  \u002F\u002F lazy — Iterator.map\n      .foldLeft(Map.empty[String, Int]) { (acc, ts) =>\n        acc.updatedWith(ts)(_.map(_ + 1).orElse(Some(1)))  \u002F\u002F O(log n) per update\n      }\n  }\n\u002F\u002F Memory: O(unique timestamps) — NOT O(file size). Iterator is the key.\n",[30,1041,1042,1047,1066,1082,1086,1128,1145,1153,1167,1190,1211,1236,1241,1246],{"__ignoreMap":28},[33,1043,1044],{"class":35,"line":36},[33,1045,1046],{"class":39},"\u002F\u002F Production pattern: process multi-GB log files without loading into memory\n",[33,1048,1049,1052,1055,1058,1061,1063],{"class":35,"line":43},[33,1050,1051],{"class":65},"import",[33,1053,1054],{"class":76}," scala",[33,1056,1057],{"class":80},".",[33,1059,1060],{"class":76},"util",[33,1062,1057],{"class":80},[33,1064,1065],{"class":76},"Using\n",[33,1067,1068,1070,1072,1074,1077,1079],{"class":35,"line":49},[33,1069,1051],{"class":65},[33,1071,1054],{"class":76},[33,1073,1057],{"class":80},[33,1075,1076],{"class":76},"io",[33,1078,1057],{"class":80},[33,1080,1081],{"class":76},"Source\n",[33,1083,1084],{"class":35,"line":56},[33,1085,53],{"emptyLinePlaceholder":52},[33,1087,1088,1091,1094,1096,1099,1102,1105,1108,1111,1113,1116,1118,1120,1122,1125],{"class":35,"line":62},[33,1089,1090],{"class":65},"def",[33,1092,1093],{"class":76}," aggregateErrors",[33,1095,81],{"class":80},[33,1097,1098],{"class":69},"path",[33,1100,1101],{"class":80},": ",[33,1103,1104],{"class":76},"String",[33,1106,1107],{"class":80},")",[33,1109,1110],{"class":65},":",[33,1112,295],{"class":76},[33,1114,1115],{"class":80},"[",[33,1117,1104],{"class":76},[33,1119,88],{"class":80},[33,1121,555],{"class":76},[33,1123,1124],{"class":80},"] ",[33,1126,1127],{"class":65},"=\n",[33,1129,1130,1133,1136,1139,1142],{"class":35,"line":105},[33,1131,1132],{"class":76},"  Using",[33,1134,1135],{"class":80},".resource(",[33,1137,1138],{"class":76},"Source",[33,1140,1141],{"class":80},".fromFile(path)) { src ",[33,1143,1144],{"class":65},"=>\n",[33,1146,1147,1150],{"class":35,"line":120},[33,1148,1149],{"class":80},"    src.getLines()                         ",[33,1151,1152],{"class":39},"\u002F\u002F Iterator[String] — lazy, line-by-line\n",[33,1154,1155,1158,1161,1164],{"class":35,"line":135},[33,1156,1157],{"class":80},"      .filter(_.contains(",[33,1159,1160],{"class":300},"\"ERROR\"",[33,1162,1163],{"class":80},"))         ",[33,1165,1166],{"class":39},"\u002F\u002F lazy — Iterator.filter\n",[33,1168,1169,1172,1174,1177,1179,1181,1184,1187],{"class":35,"line":149},[33,1170,1171],{"class":80},"      .map(line ",[33,1173,638],{"class":65},[33,1175,1176],{"class":80}," line.substring(",[33,1178,108],{"class":84},[33,1180,88],{"class":80},[33,1182,1183],{"class":84},"20",[33,1185,1186],{"class":80},"))  ",[33,1188,1189],{"class":39},"\u002F\u002F lazy — Iterator.map\n",[33,1191,1192,1195,1198,1200,1202,1204,1206,1209],{"class":35,"line":158},[33,1193,1194],{"class":80},"      .foldLeft(",[33,1196,1197],{"class":76},"Map",[33,1199,552],{"class":80},[33,1201,1104],{"class":76},[33,1203,88],{"class":80},[33,1205,555],{"class":76},[33,1207,1208],{"class":80},"]) { (acc, ts) ",[33,1210,1144],{"class":65},[33,1212,1213,1216,1218,1220,1223,1226,1228,1230,1233],{"class":35,"line":163},[33,1214,1215],{"class":80},"        acc.updatedWith(ts)(_.map(_ ",[33,1217,355],{"class":65},[33,1219,307],{"class":84},[33,1221,1222],{"class":80},").orElse(",[33,1224,1225],{"class":76},"Some",[33,1227,81],{"class":80},[33,1229,85],{"class":84},[33,1231,1232],{"class":80},")))  ",[33,1234,1235],{"class":39},"\u002F\u002F O(log n) per update\n",[33,1237,1238],{"class":35,"line":169},[33,1239,1240],{"class":80},"      }\n",[33,1242,1243],{"class":35,"line":175},[33,1244,1245],{"class":80},"  }\n",[33,1247,1248],{"class":35,"line":213},[33,1249,1250],{"class":39},"\u002F\u002F Memory: O(unique timestamps) — NOT O(file size). Iterator is the key.\n",[15,1252,1254],{"id":1253},"grouping-aggregation","Grouping & Aggregation",[20,1256,1257],{"language":22},[24,1258,1260],{"className":26,"code":1259,"language":22,"meta":28,"style":28},"final case class Order(customerId: Long, productId: Long, amount: Double)\n\nval orders: List[Order] = loadOrders()     \u002F\u002F e.g., 1M orders\n\n\u002F\u002F groupMapReduce — single-pass grouping + reduction (Scala 2.13+)\nval byCustomer: Map[Long, Double] =\n  orders.groupMapReduce(_.customerId)(_.amount)(_ + _)\n\u002F\u002F → Map[customerId → totalAmount], one traversal, one Map\n\n\u002F\u002F ❌ ANTI-PATTERN: groupBy then mapValues then sum — 3 passes + intermediate Map\nval slow = orders.groupBy(_.customerId)          \u002F\u002F pass 1: build Map of Lists\n  .view.mapValues(_.map(_.amount).sum).toMap     \u002F\u002F pass 2+3: sum each list\n\n\u002F\u002F groupMap — group + transform values in one pass\nval byProduct: Map[Long, List[Order]] =\n  orders.groupMap(_.productId)(identity)   \u002F\u002F no reduction, just group\n\n\u002F\u002F partitionMap — split into Left\u002FRight in one pass\nval (valid, invalid) = orders.partitionMap { o =>\n  if o.amount > 0 then Right(o) else Left(s\"invalid amount: ${o.amount}\")\n}\n",[30,1261,1262,1307,1311,1337,1341,1346,1369,1379,1384,1388,1393,1408,1416,1420,1425,1454,1462,1466,1471,1485,1527],{"__ignoreMap":28},[33,1263,1264,1267,1270,1273,1276,1278,1281,1283,1286,1288,1291,1293,1295,1297,1300,1302,1305],{"class":35,"line":36},[33,1265,1266],{"class":65},"final",[33,1268,1269],{"class":65}," case",[33,1271,1272],{"class":65}," class",[33,1274,1275],{"class":76}," Order",[33,1277,81],{"class":80},[33,1279,1280],{"class":69},"customerId",[33,1282,1101],{"class":80},[33,1284,1285],{"class":76},"Long",[33,1287,88],{"class":80},[33,1289,1290],{"class":69},"productId",[33,1292,1101],{"class":80},[33,1294,1285],{"class":76},[33,1296,88],{"class":80},[33,1298,1299],{"class":69},"amount",[33,1301,1101],{"class":80},[33,1303,1304],{"class":76},"Double",[33,1306,210],{"class":80},[33,1308,1309],{"class":35,"line":43},[33,1310,53],{"emptyLinePlaceholder":52},[33,1312,1313,1315,1318,1320,1322,1324,1327,1329,1331,1334],{"class":35,"line":49},[33,1314,66],{"class":65},[33,1316,1317],{"class":69}," orders",[33,1319,1110],{"class":65},[33,1321,77],{"class":76},[33,1323,1115],{"class":80},[33,1325,1326],{"class":76},"Order",[33,1328,1124],{"class":80},[33,1330,586],{"class":65},[33,1332,1333],{"class":80}," loadOrders()     ",[33,1335,1336],{"class":39},"\u002F\u002F e.g., 1M orders\n",[33,1338,1339],{"class":35,"line":56},[33,1340,53],{"emptyLinePlaceholder":52},[33,1342,1343],{"class":35,"line":62},[33,1344,1345],{"class":39},"\u002F\u002F groupMapReduce — single-pass grouping + reduction (Scala 2.13+)\n",[33,1347,1348,1350,1353,1355,1357,1359,1361,1363,1365,1367],{"class":35,"line":105},[33,1349,66],{"class":65},[33,1351,1352],{"class":69}," byCustomer",[33,1354,1110],{"class":65},[33,1356,295],{"class":76},[33,1358,1115],{"class":80},[33,1360,1285],{"class":76},[33,1362,88],{"class":80},[33,1364,1304],{"class":76},[33,1366,1124],{"class":80},[33,1368,1127],{"class":65},[33,1370,1371,1374,1376],{"class":35,"line":120},[33,1372,1373],{"class":80},"  orders.groupMapReduce(_.customerId)(_.amount)(_ ",[33,1375,355],{"class":65},[33,1377,1378],{"class":80}," _)\n",[33,1380,1381],{"class":35,"line":135},[33,1382,1383],{"class":39},"\u002F\u002F → Map[customerId → totalAmount], one traversal, one Map\n",[33,1385,1386],{"class":35,"line":149},[33,1387,53],{"emptyLinePlaceholder":52},[33,1389,1390],{"class":35,"line":158},[33,1391,1392],{"class":39},"\u002F\u002F ❌ ANTI-PATTERN: groupBy then mapValues then sum — 3 passes + intermediate Map\n",[33,1394,1395,1397,1400,1402,1405],{"class":35,"line":163},[33,1396,66],{"class":65},[33,1398,1399],{"class":69}," slow",[33,1401,73],{"class":65},[33,1403,1404],{"class":80}," orders.groupBy(_.customerId)          ",[33,1406,1407],{"class":39},"\u002F\u002F pass 1: build Map of Lists\n",[33,1409,1410,1413],{"class":35,"line":169},[33,1411,1412],{"class":80},"  .view.mapValues(_.map(_.amount).sum).toMap     ",[33,1414,1415],{"class":39},"\u002F\u002F pass 2+3: sum each list\n",[33,1417,1418],{"class":35,"line":175},[33,1419,53],{"emptyLinePlaceholder":52},[33,1421,1422],{"class":35,"line":213},[33,1423,1424],{"class":39},"\u002F\u002F groupMap — group + transform values in one pass\n",[33,1426,1427,1429,1432,1434,1436,1438,1440,1442,1445,1447,1449,1452],{"class":35,"line":227},[33,1428,66],{"class":65},[33,1430,1431],{"class":69}," byProduct",[33,1433,1110],{"class":65},[33,1435,295],{"class":76},[33,1437,1115],{"class":80},[33,1439,1285],{"class":76},[33,1441,88],{"class":80},[33,1443,1444],{"class":76},"List",[33,1446,1115],{"class":80},[33,1448,1326],{"class":76},[33,1450,1451],{"class":80},"]] ",[33,1453,1127],{"class":65},[33,1455,1456,1459],{"class":35,"line":241},[33,1457,1458],{"class":80},"  orders.groupMap(_.productId)(identity)   ",[33,1460,1461],{"class":39},"\u002F\u002F no reduction, just group\n",[33,1463,1464],{"class":35,"line":255},[33,1465,53],{"emptyLinePlaceholder":52},[33,1467,1468],{"class":35,"line":274},[33,1469,1470],{"class":39},"\u002F\u002F partitionMap — split into Left\u002FRight in one pass\n",[33,1472,1473,1475,1478,1480,1483],{"class":35,"line":279},[33,1474,66],{"class":65},[33,1476,1477],{"class":80}," (valid, invalid) ",[33,1479,586],{"class":65},[33,1481,1482],{"class":80}," orders.partitionMap { o ",[33,1484,1144],{"class":65},[33,1486,1487,1490,1493,1495,1498,1501,1504,1507,1510,1513,1515,1517,1520,1523,1525],{"class":35,"line":285},[33,1488,1489],{"class":65},"  if",[33,1491,1492],{"class":80}," o.amount ",[33,1494,773],{"class":65},[33,1496,1497],{"class":84}," 0",[33,1499,1500],{"class":65}," then",[33,1502,1503],{"class":76}," Right",[33,1505,1506],{"class":80},"(o) ",[33,1508,1509],{"class":65},"else",[33,1511,1512],{"class":76}," Left",[33,1514,81],{"class":80},[33,1516,964],{"class":65},[33,1518,1519],{"class":300},"\"invalid amount: ",[33,1521,1522],{"class":80},"${o.amount}",[33,1524,973],{"class":300},[33,1526,210],{"class":80},[33,1528,1529],{"class":35,"line":336},[33,1530,1531],{"class":80},"}\n",[15,1533,1535],{"id":1534},"mutable-collections-when-and-how","Mutable Collections — When and How",[20,1537,1538],{"language":22},[24,1539,1541],{"className":26,"code":1540,"language":22,"meta":28,"style":28},"import scala.collection.mutable\n\n\u002F\u002F ArrayBuffer: growable array. O(1) append (amortized), O(1) random access.\n\u002F\u002F Backed by a Java ArrayList-like structure. Doubles capacity when full.\nval buf = mutable.ArrayBuffer.empty[Int]\nfor i \u003C- 1 to 10000 do buf += i            \u002F\u002F O(1) amortized — occasional resize copies\nval arr = buf.toArray                       \u002F\u002F O(n) copy to primitive int[] (if buf is ArrayBuffer[Int])\n\n\u002F\u002F ❌ ANTI-PATTERN: returning mutable collections from APIs\ndef getUsers: mutable.Map[Long, User] = mutable.Map(...)  \u002F\u002F caller can mutate internal state!\n\u002F\u002F ✅ CORRECT: convert to immutable before returning\ndef getUsers: Map[Long, User] = mutable.Map(...).toMap    \u002F\u002F defensive copy, caller can't mutate\n\n\u002F\u002F ArrayStack \u002F ArrayDeque: O(1) prepend AND append (ring buffer)\nval deque = mutable.ArrayDeque.empty[Int]\ndeque.append(1)                            \u002F\u002F O(1)\ndeque.prepend(0)                           \u002F\u002F O(1) — unlike ArrayBuffer's O(n) prepend\n\n\u002F\u002F HashMap (mutable): O(1) average, O(n) worst-case (hash collision)\nval cache = mutable.HashMap.empty[String, Array[Byte]]\ncache.put(\"key1\", data)                    \u002F\u002F O(1) average\ncache.getOrElseUpdate(\"key2\", compute())   \u002F\u002F O(1) — compute only if missing (atomic)\n",[30,1542,1543,1559,1563,1568,1573,1594,1621,1636,1640,1645,1681,1686,1718,1722,1727,1747,1760,1772,1776,1781,1812,1826],{"__ignoreMap":28},[33,1544,1545,1547,1549,1551,1554,1556],{"class":35,"line":36},[33,1546,1051],{"class":65},[33,1548,1054],{"class":76},[33,1550,1057],{"class":80},[33,1552,1553],{"class":76},"collection",[33,1555,1057],{"class":80},[33,1557,1558],{"class":76},"mutable\n",[33,1560,1561],{"class":35,"line":43},[33,1562,53],{"emptyLinePlaceholder":52},[33,1564,1565],{"class":35,"line":49},[33,1566,1567],{"class":39},"\u002F\u002F ArrayBuffer: growable array. O(1) append (amortized), O(1) random access.\n",[33,1569,1570],{"class":35,"line":56},[33,1571,1572],{"class":39},"\u002F\u002F Backed by a Java ArrayList-like structure. Doubles capacity when full.\n",[33,1574,1575,1577,1580,1582,1585,1588,1590,1592],{"class":35,"line":62},[33,1576,66],{"class":65},[33,1578,1579],{"class":69}," buf",[33,1581,73],{"class":65},[33,1583,1584],{"class":80}," mutable.",[33,1586,1587],{"class":76},"ArrayBuffer",[33,1589,552],{"class":80},[33,1591,555],{"class":76},[33,1593,558],{"class":80},[33,1595,1596,1598,1600,1602,1604,1606,1608,1610,1613,1615,1618],{"class":35,"line":105},[33,1597,563],{"class":65},[33,1599,566],{"class":80},[33,1601,569],{"class":65},[33,1603,307],{"class":84},[33,1605,574],{"class":80},[33,1607,577],{"class":84},[33,1609,580],{"class":65},[33,1611,1612],{"class":80}," buf ",[33,1614,694],{"class":65},[33,1616,1617],{"class":80}," i            ",[33,1619,1620],{"class":39},"\u002F\u002F O(1) amortized — occasional resize copies\n",[33,1622,1623,1625,1628,1630,1633],{"class":35,"line":120},[33,1624,66],{"class":65},[33,1626,1627],{"class":69}," arr",[33,1629,73],{"class":65},[33,1631,1632],{"class":80}," buf.toArray                       ",[33,1634,1635],{"class":39},"\u002F\u002F O(n) copy to primitive int[] (if buf is ArrayBuffer[Int])\n",[33,1637,1638],{"class":35,"line":135},[33,1639,53],{"emptyLinePlaceholder":52},[33,1641,1642],{"class":35,"line":149},[33,1643,1644],{"class":39},"\u002F\u002F ❌ ANTI-PATTERN: returning mutable collections from APIs\n",[33,1646,1647,1649,1652,1654,1656,1658,1660,1662,1664,1667,1669,1671,1673,1675,1678],{"class":35,"line":158},[33,1648,1090],{"class":65},[33,1650,1651],{"class":76}," getUsers",[33,1653,1110],{"class":65},[33,1655,1584],{"class":80},[33,1657,1197],{"class":76},[33,1659,1115],{"class":80},[33,1661,1285],{"class":76},[33,1663,88],{"class":80},[33,1665,1666],{"class":76},"User",[33,1668,1124],{"class":80},[33,1670,586],{"class":65},[33,1672,1584],{"class":80},[33,1674,1197],{"class":76},[33,1676,1677],{"class":80},"(...)  ",[33,1679,1680],{"class":39},"\u002F\u002F caller can mutate internal state!\n",[33,1682,1683],{"class":35,"line":163},[33,1684,1685],{"class":39},"\u002F\u002F ✅ CORRECT: convert to immutable before returning\n",[33,1687,1688,1690,1692,1694,1696,1698,1700,1702,1704,1706,1708,1710,1712,1715],{"class":35,"line":169},[33,1689,1090],{"class":65},[33,1691,1651],{"class":76},[33,1693,1110],{"class":65},[33,1695,295],{"class":76},[33,1697,1115],{"class":80},[33,1699,1285],{"class":76},[33,1701,88],{"class":80},[33,1703,1666],{"class":76},[33,1705,1124],{"class":80},[33,1707,586],{"class":65},[33,1709,1584],{"class":80},[33,1711,1197],{"class":76},[33,1713,1714],{"class":80},"(...).toMap    ",[33,1716,1717],{"class":39},"\u002F\u002F defensive copy, caller can't mutate\n",[33,1719,1720],{"class":35,"line":175},[33,1721,53],{"emptyLinePlaceholder":52},[33,1723,1724],{"class":35,"line":213},[33,1725,1726],{"class":39},"\u002F\u002F ArrayStack \u002F ArrayDeque: O(1) prepend AND append (ring buffer)\n",[33,1728,1729,1731,1734,1736,1738,1741,1743,1745],{"class":35,"line":227},[33,1730,66],{"class":65},[33,1732,1733],{"class":69}," deque",[33,1735,73],{"class":65},[33,1737,1584],{"class":80},[33,1739,1740],{"class":76},"ArrayDeque",[33,1742,552],{"class":80},[33,1744,555],{"class":76},[33,1746,558],{"class":80},[33,1748,1749,1752,1754,1757],{"class":35,"line":241},[33,1750,1751],{"class":80},"deque.append(",[33,1753,85],{"class":84},[33,1755,1756],{"class":80},")                            ",[33,1758,1759],{"class":39},"\u002F\u002F O(1)\n",[33,1761,1762,1765,1767,1769],{"class":35,"line":255},[33,1763,1764],{"class":80},"deque.prepend(",[33,1766,108],{"class":84},[33,1768,461],{"class":80},[33,1770,1771],{"class":39},"\u002F\u002F O(1) — unlike ArrayBuffer's O(n) prepend\n",[33,1773,1774],{"class":35,"line":274},[33,1775,53],{"emptyLinePlaceholder":52},[33,1777,1778],{"class":35,"line":279},[33,1779,1780],{"class":39},"\u002F\u002F HashMap (mutable): O(1) average, O(n) worst-case (hash collision)\n",[33,1782,1783,1785,1788,1790,1792,1795,1797,1799,1801,1804,1806,1809],{"class":35,"line":285},[33,1784,66],{"class":65},[33,1786,1787],{"class":69}," cache",[33,1789,73],{"class":65},[33,1791,1584],{"class":80},[33,1793,1794],{"class":76},"HashMap",[33,1796,552],{"class":80},[33,1798,1104],{"class":76},[33,1800,88],{"class":80},[33,1802,1803],{"class":76},"Array",[33,1805,1115],{"class":80},[33,1807,1808],{"class":76},"Byte",[33,1810,1811],{"class":80},"]]\n",[33,1813,1814,1817,1820,1823],{"class":35,"line":336},[33,1815,1816],{"class":80},"cache.put(",[33,1818,1819],{"class":300},"\"key1\"",[33,1821,1822],{"class":80},", data)                    ",[33,1824,1825],{"class":39},"\u002F\u002F O(1) average\n",[33,1827,1828,1831,1834,1837],{"class":35,"line":349},[33,1829,1830],{"class":80},"cache.getOrElseUpdate(",[33,1832,1833],{"class":300},"\"key2\"",[33,1835,1836],{"class":80},", compute())   ",[33,1838,1839],{"class":39},"\u002F\u002F O(1) — compute only if missing (atomic)\n",[15,1841,1843],{"id":1842},"zipping-folding-and-scanning","Zipping, Folding, and Scanning",[20,1845,1846],{"language":22},[24,1847,1849],{"className":26,"code":1848,"language":22,"meta":28,"style":28},"\u002F\u002F foldLeft vs foldRight — evaluation order matters for non-associative ops\nList(1, 2, 3).foldLeft(0)(_ - _)            \u002F\u002F → ((0 - 1) - 2) - 3 = -6  (left-to-right)\nList(1, 2, 3).foldRight(0)(_ - _)           \u002F\u002F → 1 - (2 - (3 - 0)) = 2   (right-to-left)\n\u002F\u002F foldRight is NOT tail-recursive on List → stack overflow on long lists!\n\u002F\u002F Use foldLeft for linear folds. Use reduceLeftOption for empty-safe reduction.\n\n\u002F\u002F scanLeft — running accumulation (prefix sums)\nList(1, 2, 3, 4).scanLeft(0)(_ + _)         \u002F\u002F → List(0, 1, 3, 6, 10) — includes initial\n\n\u002F\u002F zipAll — pad shorter collection with default\nList(1, 2, 3).zipAll(List(\"a\", \"b\"), 0, \"?\")  \u002F\u002F → List((1,\"a\"), (2,\"b\"), (3,\"?\"))\n\n\u002F\u002F zipWithIndex — pair each element with its index (O(n), no random access needed)\n\"hello\".zipWithIndex                       \u002F\u002F → Vector(('h',0), ('e',1), ('l',2), ('l',3), ('o',4))\n\n\u002F\u002F ❌ ANTI-PATTERN: using .zipWithIndex then .map for indexed transformation\n\u002F\u002F ✅ CORRECT: use .indices.map or .zipWithIndex in a single pass\n",[30,1850,1851,1856,1887,1918,1923,1928,1932,1937,1972,1976,1981,2025,2029,2034,2045,2049,2054],{"__ignoreMap":28},[33,1852,1853],{"class":35,"line":36},[33,1854,1855],{"class":39},"\u002F\u002F foldLeft vs foldRight — evaluation order matters for non-associative ops\n",[33,1857,1858,1860,1862,1864,1866,1868,1870,1872,1874,1876,1879,1881,1884],{"class":35,"line":43},[33,1859,1444],{"class":76},[33,1861,81],{"class":80},[33,1863,85],{"class":84},[33,1865,88],{"class":80},[33,1867,91],{"class":84},[33,1869,88],{"class":80},[33,1871,96],{"class":84},[33,1873,625],{"class":80},[33,1875,108],{"class":84},[33,1877,1878],{"class":80},")(_ ",[33,1880,379],{"class":65},[33,1882,1883],{"class":80}," _)            ",[33,1885,1886],{"class":39},"\u002F\u002F → ((0 - 1) - 2) - 3 = -6  (left-to-right)\n",[33,1888,1889,1891,1893,1895,1897,1899,1901,1903,1906,1908,1910,1912,1915],{"class":35,"line":49},[33,1890,1444],{"class":76},[33,1892,81],{"class":80},[33,1894,85],{"class":84},[33,1896,88],{"class":80},[33,1898,91],{"class":84},[33,1900,88],{"class":80},[33,1902,96],{"class":84},[33,1904,1905],{"class":80},").foldRight(",[33,1907,108],{"class":84},[33,1909,1878],{"class":80},[33,1911,379],{"class":65},[33,1913,1914],{"class":80}," _)           ",[33,1916,1917],{"class":39},"\u002F\u002F → 1 - (2 - (3 - 0)) = 2   (right-to-left)\n",[33,1919,1920],{"class":35,"line":56},[33,1921,1922],{"class":39},"\u002F\u002F foldRight is NOT tail-recursive on List → stack overflow on long lists!\n",[33,1924,1925],{"class":35,"line":62},[33,1926,1927],{"class":39},"\u002F\u002F Use foldLeft for linear folds. Use reduceLeftOption for empty-safe reduction.\n",[33,1929,1930],{"class":35,"line":105},[33,1931,53],{"emptyLinePlaceholder":52},[33,1933,1934],{"class":35,"line":120},[33,1935,1936],{"class":39},"\u002F\u002F scanLeft — running accumulation (prefix sums)\n",[33,1938,1939,1941,1943,1945,1947,1949,1951,1953,1955,1957,1960,1962,1964,1966,1969],{"class":35,"line":135},[33,1940,1444],{"class":76},[33,1942,81],{"class":80},[33,1944,85],{"class":84},[33,1946,88],{"class":80},[33,1948,91],{"class":84},[33,1950,88],{"class":80},[33,1952,96],{"class":84},[33,1954,88],{"class":80},[33,1956,202],{"class":84},[33,1958,1959],{"class":80},").scanLeft(",[33,1961,108],{"class":84},[33,1963,1878],{"class":80},[33,1965,355],{"class":65},[33,1967,1968],{"class":80}," _)         ",[33,1970,1971],{"class":39},"\u002F\u002F → List(0, 1, 3, 6, 10) — includes initial\n",[33,1973,1974],{"class":35,"line":149},[33,1975,53],{"emptyLinePlaceholder":52},[33,1977,1978],{"class":35,"line":158},[33,1979,1980],{"class":39},"\u002F\u002F zipAll — pad shorter collection with default\n",[33,1982,1983,1985,1987,1989,1991,1993,1995,1997,2000,2002,2004,2006,2008,2010,2013,2015,2017,2020,2022],{"class":35,"line":163},[33,1984,1444],{"class":76},[33,1986,81],{"class":80},[33,1988,85],{"class":84},[33,1990,88],{"class":80},[33,1992,91],{"class":84},[33,1994,88],{"class":80},[33,1996,96],{"class":84},[33,1998,1999],{"class":80},").zipAll(",[33,2001,1444],{"class":76},[33,2003,81],{"class":80},[33,2005,301],{"class":300},[33,2007,88],{"class":80},[33,2009,312],{"class":300},[33,2011,2012],{"class":80},"), ",[33,2014,108],{"class":84},[33,2016,88],{"class":80},[33,2018,2019],{"class":300},"\"?\"",[33,2021,330],{"class":80},[33,2023,2024],{"class":39},"\u002F\u002F → List((1,\"a\"), (2,\"b\"), (3,\"?\"))\n",[33,2026,2027],{"class":35,"line":169},[33,2028,53],{"emptyLinePlaceholder":52},[33,2030,2031],{"class":35,"line":175},[33,2032,2033],{"class":39},"\u002F\u002F zipWithIndex — pair each element with its index (O(n), no random access needed)\n",[33,2035,2036,2039,2042],{"class":35,"line":213},[33,2037,2038],{"class":300},"\"hello\"",[33,2040,2041],{"class":80},".zipWithIndex                       ",[33,2043,2044],{"class":39},"\u002F\u002F → Vector(('h',0), ('e',1), ('l',2), ('l',3), ('o',4))\n",[33,2046,2047],{"class":35,"line":227},[33,2048,53],{"emptyLinePlaceholder":52},[33,2050,2051],{"class":35,"line":241},[33,2052,2053],{"class":39},"\u002F\u002F ❌ ANTI-PATTERN: using .zipWithIndex then .map for indexed transformation\n",[33,2055,2056],{"class":35,"line":255},[33,2057,2058],{"class":39},"\u002F\u002F ✅ CORRECT: use .indices.map or .zipWithIndex in a single pass\n",[15,2060,2062],{"id":2061},"tips-tricks","💡 Tips & Tricks",[2064,2065,2066,2073,2074,2077],"p",{},[2067,2068,2069,2072],"strong",{},[30,2070,2071],{},".iterator"," for memory-bounded processing",": Any collection can produce an ",[30,2075,2076],{},"Iterator"," — lazy, one-pass, O(1) memory. Use for streaming or large datasets.",[20,2079,2080],{"language":22},[24,2081,2083],{"className":26,"code":2082,"language":22,"meta":28,"style":28},"\u002F\u002F Stream a 10GB file line-by-line — constant memory\nio.Source.fromFile(\"huge.log\").getLines()\n  .filter(_.contains(\"ERROR\"))\n  .foreach(println)                        \u002F\u002F never holds more than 1 line in memory\n",[30,2084,2085,2090,2106,2116],{"__ignoreMap":28},[33,2086,2087],{"class":35,"line":36},[33,2088,2089],{"class":39},"\u002F\u002F Stream a 10GB file line-by-line — constant memory\n",[33,2091,2092,2095,2097,2100,2103],{"class":35,"line":43},[33,2093,2094],{"class":80},"io.",[33,2096,1138],{"class":76},[33,2098,2099],{"class":80},".fromFile(",[33,2101,2102],{"class":300},"\"huge.log\"",[33,2104,2105],{"class":80},").getLines()\n",[33,2107,2108,2111,2113],{"class":35,"line":49},[33,2109,2110],{"class":80},"  .filter(_.contains(",[33,2112,1160],{"class":300},[33,2114,2115],{"class":80},"))\n",[33,2117,2118,2121],{"class":35,"line":56},[33,2119,2120],{"class":80},"  .foreach(println)                        ",[33,2122,2123],{"class":39},"\u002F\u002F never holds more than 1 line in memory\n",[2064,2125,2126,2131],{},[2067,2127,2128,2130],{},[30,2129,628],{}," is the default immutable choice",": Unless you specifically need O(1) prepend (List) or sorted access (TreeMap), use Vector. It's the most balanced persistent collection.",[2064,2133,2134,2140],{},[2067,2135,2136,2139],{},[30,2137,2138],{},".updatedWith"," for conditional Map updates",": Atomic check-and-update in one call.",[20,2142,2143],{"language":22},[24,2144,2146],{"className":26,"code":2145,"language":22,"meta":28,"style":28},"cache.updatedWith(key)(_.map(_ + 1).orElse(Some(1)))  \u002F\u002F increment or initialize to 1\n",[30,2147,2148],{"__ignoreMap":28},[33,2149,2150,2153,2155,2157,2159,2161,2163,2165,2167],{"class":35,"line":36},[33,2151,2152],{"class":80},"cache.updatedWith(key)(_.map(_ ",[33,2154,355],{"class":65},[33,2156,307],{"class":84},[33,2158,1222],{"class":80},[33,2160,1225],{"class":76},[33,2162,81],{"class":80},[33,2164,85],{"class":84},[33,2166,1232],{"class":80},[33,2168,2169],{"class":39},"\u002F\u002F increment or initialize to 1\n",[15,2171,2173],{"id":2172},"️-edge-cases-gotchas","⚠️ Edge Cases & Gotchas",[2064,2175,2176,1101,2185,2188,2189,2191],{},[2067,2177,2178,2180,2181,2184],{},[30,2179,1444],{}," ",[30,2182,2183],{},"reverse"," is O(n) and non-lazy",[30,2186,2187],{},"list.reverse.reverse"," is O(2n) — not free. Don't use ",[30,2190,2183],{}," to \"work around\" the prepend-only nature of List in hot paths.",[2064,2193,2194,1101,2200,2203,2204,2207,2208,2211],{},[2067,2195,2196,2199],{},[30,2197,2198],{},"Range"," overflow",[30,2201,2202],{},"(1 to Int.MaxValue)"," can cause arithmetic overflow in the Range implementation. Use ",[30,2205,2206],{},"1.until(Int.MaxValue)"," or iterate with a ",[30,2209,2210],{},"while"," loop for extreme ranges.",[2064,2213,2214,1101,2220,2223,2224,2227,2228,2231,2232,2235,2236,1057],{},[2067,2215,2216,2219],{},[30,2217,2218],{},"Map.apply"," throws on missing key",[30,2221,2222],{},"map(\"missing\")"," throws ",[30,2225,2226],{},"NoSuchElementException",". Use ",[30,2229,2230],{},"map.get(\"missing\")"," (returns ",[30,2233,2234],{},"Option",") or ",[30,2237,2238],{},"map.getOrElse(\"missing\", default)",[2064,2240,2241,2247],{},[2067,2242,2243,2246],{},[30,2244,2245],{},"view"," + side effects = confusion",": View operations are re-evaluated on each force. If the pipeline has side effects (logging, counters), they fire N times for N forces.",[2064,2249,2250,1101,2255,2258,2259,2262,2263,2266],{},[2067,2251,2252,2254],{},[30,2253,1803],{}," is invariant",[30,2256,2257],{},"Array[Int]"," is NOT a subtype of ",[30,2260,2261],{},"Array[Any]"," (unlike Java's array covariance). This prevents ",[30,2264,2265],{},"ArrayStoreException"," at the type level — a deliberate Scala fix.",[15,2268,2270],{"id":2269},"quick-quiz","🧠 Quick Quiz",[2064,2272,2273,2274,2277,2278,2281],{},"Why does ",[30,2275,2276],{},"Vector(1,2,3).map(_ * 2).map(_ + 1)"," allocate fewer objects than ",[30,2279,2280],{},"List(1,2,3).map(_ * 2).map(_ + 1)","?",[2283,2284,2285,2289,2333,2350],"details",{},[2286,2287,2288],"summary",{},"Answer",[2290,2291,2292,2320],"ul",{},[2293,2294,2295,2297,2298,2301,2302,2305,2306,2309,2310,2313,2314,2316,2317,2319],"li",{},[2067,2296,1444],{},": Each ",[30,2299,2300],{},"map"," traverses the list and creates new cons cells. ",[30,2303,2304],{},"map(_ * 2)"," → 3 ",[30,2307,2308],{},"::"," cells. ",[30,2311,2312],{},"map(_ + 1)"," → 3 more ",[30,2315,2308],{}," cells. Total: 6 cons cells + 2 intermediate ",[30,2318,1444],{}," objects.",[2293,2321,2322,2297,2324,2326,2327,2329,2330,2332],{},[2067,2323,628],{},[30,2325,2300],{}," builds a new RRB-tree. For a 3-element Vector (1 level), ",[30,2328,2304],{}," copies 1 leaf node + 1 root node. ",[30,2331,2312],{}," copies another 1 leaf + 1 root. Total: 4 nodes (2 leaves + 2 roots). But the tree structure means the root is a new object pointing to a new leaf.",[2064,2334,2335,2336,2339,2340,2343,2344,2346,2347,2349],{},"For ",[2067,2337,2338],{},"small collections"," (n \u003C 32), both are O(n) allocations. For ",[2067,2341,2342],{},"large collections"," (n = 1M), Vector's ",[30,2345,2300],{}," copies only the leaf level (~31K leaves for 1M elements) while keeping the tree structure. List's ",[30,2348,2300],{}," copies all 1M cons cells.",[2064,2351,2352,2353,2359],{},"The real win: ",[2067,2354,2355,2356],{},"Vector + ",[30,2357,2358],{},".view"," — zero intermediate collections, single-pass evaluation.",[2361,2362,2363],"style",{},"html pre.shiki code .sdCPZ, html code.shiki .sdCPZ{--shiki-default:#6A737D;--shiki-github-dark:#6A737D}html pre.shiki code .svdQ7, html code.shiki .svdQ7{--shiki-default:#D73A49;--shiki-github-dark:#F97583}html pre.shiki code .sCrzJ, html code.shiki .sCrzJ{--shiki-default:#E36209;--shiki-github-dark:#FFAB70}html pre.shiki code .sIsaT, html code.shiki .sIsaT{--shiki-default:#6F42C1;--shiki-github-dark:#B392F0}html pre.shiki code .ssxIu, html code.shiki .ssxIu{--shiki-default:#24292E;--shiki-github-dark:#E1E4E8}html pre.shiki code .snvgF, html code.shiki .snvgF{--shiki-default:#005CC5;--shiki-github-dark:#79B8FF}html pre.shiki code .sJ6F3, html code.shiki .sJ6F3{--shiki-default:#032F62;--shiki-github-dark:#9ECBFF}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .github-dark .shiki span {color: var(--shiki-github-dark);background: var(--shiki-github-dark-bg);font-style: var(--shiki-github-dark-font-style);font-weight: var(--shiki-github-dark-font-weight);text-decoration: var(--shiki-github-dark-text-decoration);}html.github-dark .shiki span {color: var(--shiki-github-dark);background: var(--shiki-github-dark-bg);font-style: var(--shiki-github-dark-font-style);font-weight: var(--shiki-github-dark-font-weight);text-decoration: var(--shiki-github-dark-text-decoration);}",{"title":28,"searchDepth":43,"depth":43,"links":2365},[2366,2367,2368,2369,2370,2371,2372,2373,2374,2375,2376],{"id":17,"depth":43,"text":18},{"id":467,"depth":43,"text":468},{"id":715,"depth":43,"text":716},{"id":1019,"depth":43,"text":1020},{"id":1033,"depth":43,"text":1034},{"id":1253,"depth":43,"text":1254},{"id":1534,"depth":43,"text":1535},{"id":1842,"depth":43,"text":1843},{"id":2061,"depth":43,"text":2062},{"id":2172,"depth":43,"text":2173},{"id":2269,"depth":43,"text":2270},"md",{},"\u002Fscala\u002F05-collections",{"title":2381,"description":28},{"Scala — Collections":2382,"description":2383},"Persistent Data Structures & Fusion","Production deep-dive into Scala's persistent immutable collections, Vector RRB-trees, lazy views, streaming fusion, and performance characteristics of each collection type.","scala\u002F05-collections","s5wsQ_DglWS2u3QxDpZu3qFqJjVHa2AmTSIYH2R0tY4",1789924653976]