@icarusmx/creta 1.5.4 → 1.5.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (31) hide show
  1. package/lib/builders/MenuBuilder.js +23 -4
  2. package/lib/exercises/array-object-manipulation.md +1281 -0
  3. package/lib/exercises/git-stash-workflow.md +426 -0
  4. package/lib/exercises/railway-deployment.md +1185 -0
  5. package/lib/papers/bitcoin/bitcoin.md +92 -0
  6. package/lib/papers/mapreduce/mapreduce.md +476 -0
  7. package/lib/papers/spark/spark.md +49 -0
  8. package/package.json +5 -1
  9. package/ascii-logo.txt +0 -8
  10. package/codex-refactor.txt +0 -13
  11. package/docs/diagrams/README.md +0 -131
  12. package/docs/diagrams/architecture-overview.mmd +0 -71
  13. package/docs/diagrams/architecture.svg +0 -1
  14. package/docs/diagrams/ecosystem-integration.mmd +0 -49
  15. package/docs/diagrams/evolution-phases.mmd +0 -49
  16. package/docs/diagrams/output.svg +0 -1
  17. package/docs/diagrams/phase2-command-help-flow.mmd +0 -51
  18. package/docs/diagrams/user-journey.mmd +0 -78
  19. package/ejemplo.sh +0 -3
  20. package/refactor.txt +0 -581
  21. package/templates/sveltekit-portfolio/package.json +0 -20
  22. package/templates/sveltekit-portfolio/src/app.css +0 -51
  23. package/templates/sveltekit-portfolio/src/app.html +0 -12
  24. package/templates/sveltekit-portfolio/src/routes/+layout.svelte +0 -108
  25. package/templates/sveltekit-portfolio/src/routes/+page.svelte +0 -79
  26. package/templates/sveltekit-portfolio/static/favicon.png +0 -0
  27. package/templates/sveltekit-portfolio/svelte.config.js +0 -10
  28. package/templates/sveltekit-portfolio/vite.config.js +0 -10
  29. package/test/enunciados.test.js +0 -72
  30. package/test/sintaxis-menu.test.js +0 -45
  31. package/wea-fome-qlia.sh +0 -92
@@ -0,0 +1,1281 @@
1
+ # Array & Object Manipulation Warmups
2
+
3
+ <!-- vim: set foldmethod=marker foldlevel=0: -->
4
+
5
+ ## 📖 LazyVim Reading Guide {{{
6
+
7
+ **Start with:** `zM` (close all folds) → Navigate with `za` (toggle fold under cursor)
8
+
9
+ This document uses fold markers `{{{` and `}}}` for organized reading.
10
+
11
+ **Navigation Tips:**
12
+ - `zM` - Close all folds (see just section headers)
13
+ - `zR` - Open all folds (see everything)
14
+ - `za` - Toggle current fold
15
+ - `zj` - Jump to next fold
16
+ - `zk` - Jump to previous fold
17
+
18
+ }}}
19
+
20
+ ## 🎯 Learning Path {{{
21
+
22
+ This document progresses from **basic object access** to **advanced array transformations**:
23
+
24
+ 1. **Level 1: Objects** - Access, modify, destructure
25
+ 2. **Level 2: Basic Arrays** - Map, filter, find
26
+ 3. **Level 3: Array of Objects** - Query, transform, aggregate
27
+ 4. **Level 4: Advanced Patterns** - Reduce, grouping, chaining
28
+
29
+ **How to practice:**
30
+ - Copy exercise to a `.js` file
31
+ - Use `node filename.js` to test
32
+ - Try solving WITHOUT looking at solution first
33
+ - Compare your solution with the provided one
34
+
35
+ }}}
36
+
37
+ ## 💡 LazyVim Editing Tips {{{
38
+
39
+ ### Quick Object/Array Navigation {{{
40
+
41
+ ```javascript
42
+ // Use these motions in LazyVim:
43
+ const user = {
44
+ name: "Ana", // ci{ inside curly braces
45
+ age: 25, // % jump to matching bracket
46
+ city: "CDMX" // va{ select around object (includes {})
47
+ }
48
+ ```
49
+
50
+ **Key Motions:**
51
+ - `%` - Jump between matching brackets `{}`, `[]`, `()`
52
+ - `ci{` - Change inside `{}`
53
+ - `di[` - Delete inside `[]`
54
+ - `va{` - Visual select around `{}` (includes braces)
55
+ - `vi[` - Visual select inside `[]` (excludes brackets)
56
+ - `>>` - Indent line
57
+ - `<<` - Unindent line
58
+ - `=i{` - Auto-format inside `{}`
59
+
60
+ }}}
61
+
62
+ ### Array Manipulation Shortcuts {{{
63
+
64
+ ```javascript
65
+ // Working with arrays in LazyVim:
66
+ const nums = [1, 2, 3, 4, 5]
67
+ // ↑ ↑
68
+ // ci[ press % to jump
69
+ ```
70
+
71
+ **Multi-line arrays:**
72
+ - `V` - Visual line mode
73
+ - `>` - Indent selected lines
74
+ - `<` - Unindent selected lines
75
+ - `=` - Auto-format selection
76
+
77
+ **Duplicate lines:**
78
+ - `yyp` - Yank current line and paste below
79
+ - `5yyp` - Copy current line 5 times below
80
+ - `Vj:t.` - Duplicate visual selection
81
+
82
+ }}}
83
+
84
+ ### Search & Replace in Objects {{{
85
+
86
+ **Find all properties:**
87
+ ```vim
88
+ /\w\+: " Find all property names (word + colon)
89
+ ```
90
+
91
+ **Replace property names:**
92
+ ```vim
93
+ :%s/nombre/name/g " Replace 'nombre' with 'name' globally
94
+ :%s/\(\w\+\):/"\1":/g " Add quotes around all property names
95
+ ```
96
+
97
+ **Multi-cursor editing:**
98
+ - `<C-n>` - Start multi-cursor on word under cursor
99
+ - `<C-n>` again - Add next match
100
+ - `<C-x>` - Skip current match
101
+ - Type to edit all at once
102
+
103
+ }}}
104
+
105
+ }}}
106
+
107
+ ## Level 1: Object Fundamentals {{{
108
+
109
+ ### Warmup 1.1: Object Access {{{
110
+
111
+ **Exercise:**
112
+ ```javascript
113
+ const product = {
114
+ id: 101,
115
+ name: "Laptop",
116
+ price: 15000,
117
+ inStock: true
118
+ }
119
+
120
+ // TODO: Access and print:
121
+ // 1. Product name
122
+ // 2. Product price
123
+ // 3. Check if in stock
124
+ ```
125
+
126
+ **Solution:**
127
+ ```javascript
128
+ const product = {
129
+ id: 101,
130
+ name: "Laptop",
131
+ price: 15000,
132
+ inStock: true
133
+ }
134
+
135
+ console.log(product.name) // "Laptop"
136
+ console.log(product.price) // 15000
137
+ console.log(product.inStock) // true
138
+
139
+ // Alternative: bracket notation
140
+ console.log(product['name']) // "Laptop"
141
+ ```
142
+
143
+ **LazyVim Tip:** Place cursor on `product` and press `gd` to jump to definition.
144
+
145
+ }}}
146
+
147
+ ### Warmup 1.2: Object Modification {{{
148
+
149
+ **Exercise:**
150
+ ```javascript
151
+ const user = {
152
+ username: "ana_dev",
153
+ email: "ana@example.com",
154
+ verified: false
155
+ }
156
+
157
+ // TODO:
158
+ // 1. Change verified to true
159
+ // 2. Add a new property: role = "developer"
160
+ // 3. Delete the email property
161
+ ```
162
+
163
+ **Solution:**
164
+ ```javascript
165
+ const user = {
166
+ username: "ana_dev",
167
+ email: "ana@example.com",
168
+ verified: false
169
+ }
170
+
171
+ // 1. Modify property
172
+ user.verified = true
173
+
174
+ // 2. Add new property
175
+ user.role = "developer"
176
+
177
+ // 3. Delete property
178
+ delete user.email
179
+
180
+ console.log(user)
181
+ // { username: "ana_dev", verified: true, role: "developer" }
182
+ ```
183
+
184
+ **LazyVim Tip:** Use `ciw` (change inner word) to quickly edit property values.
185
+
186
+ }}}
187
+
188
+ ### Warmup 1.3: Object Destructuring {{{
189
+
190
+ **Exercise:**
191
+ ```javascript
192
+ const config = {
193
+ host: "localhost",
194
+ port: 3000,
195
+ timeout: 5000,
196
+ retries: 3
197
+ }
198
+
199
+ // TODO: Extract host and port using destructuring
200
+ ```
201
+
202
+ **Solution:**
203
+ ```javascript
204
+ const config = {
205
+ host: "localhost",
206
+ port: 3000,
207
+ timeout: 5000,
208
+ retries: 3
209
+ }
210
+
211
+ // Basic destructuring
212
+ const { host, port } = config
213
+ console.log(host) // "localhost"
214
+ console.log(port) // 3000
215
+
216
+ // With renaming
217
+ const { host: serverHost, port: serverPort } = config
218
+ console.log(serverHost) // "localhost"
219
+
220
+ // With default values
221
+ const { ssl = false } = config
222
+ console.log(ssl) // false (property doesn't exist)
223
+ ```
224
+
225
+ **LazyVim Tip:** Use `%` to jump between matching braces when editing destructuring.
226
+
227
+ }}}
228
+
229
+ ### Warmup 1.4: Nested Objects {{{
230
+
231
+ **Exercise:**
232
+ ```javascript
233
+ const developer = {
234
+ name: "Carlos",
235
+ skills: {
236
+ languages: ["JavaScript", "Python"],
237
+ frameworks: ["React", "Express"]
238
+ },
239
+ experience: {
240
+ years: 3,
241
+ level: "mid"
242
+ }
243
+ }
244
+
245
+ // TODO:
246
+ // 1. Access the first language
247
+ // 2. Access experience level
248
+ // 3. Add "Node.js" to frameworks
249
+ ```
250
+
251
+ **Solution:**
252
+ ```javascript
253
+ const developer = {
254
+ name: "Carlos",
255
+ skills: {
256
+ languages: ["JavaScript", "Python"],
257
+ frameworks: ["React", "Express"]
258
+ },
259
+ experience: {
260
+ years: 3,
261
+ level: "mid"
262
+ }
263
+ }
264
+
265
+ // 1. Access nested array
266
+ console.log(developer.skills.languages[0]) // "JavaScript"
267
+
268
+ // 2. Access nested object
269
+ console.log(developer.experience.level) // "mid"
270
+
271
+ // 3. Modify nested array
272
+ developer.skills.frameworks.push("Node.js")
273
+ console.log(developer.skills.frameworks)
274
+ // ["React", "Express", "Node.js"]
275
+ ```
276
+
277
+ **LazyVim Tip:** Use `vi{` to select inside object, then `=` to auto-format.
278
+
279
+ }}}
280
+
281
+ }}}
282
+
283
+ ## Level 2: Array Fundamentals {{{
284
+
285
+ ### Warmup 2.1: Array.map() - Transform {{{
286
+
287
+ **Exercise:**
288
+ ```javascript
289
+ const prices = [100, 250, 500, 1000]
290
+
291
+ // TODO: Create new array with 16% tax added to each price
292
+ ```
293
+
294
+ **Solution:**
295
+ ```javascript
296
+ const prices = [100, 250, 500, 1000]
297
+
298
+ const pricesWithTax = prices.map(price => price * 1.16)
299
+ console.log(pricesWithTax)
300
+ // [116, 290, 580, 1160]
301
+
302
+ // Longer form (same result):
303
+ const pricesWithTax2 = prices.map(function(price) {
304
+ return price * 1.16
305
+ })
306
+ ```
307
+
308
+ **LazyVim Tip:** Select the array with `vi[` and press `>` to indent for readability.
309
+
310
+ }}}
311
+
312
+ ### Warmup 2.2: Array.filter() - Select {{{
313
+
314
+ **Exercise:**
315
+ ```javascript
316
+ const numbers = [5, 12, 8, 130, 44, 3, 21]
317
+
318
+ // TODO:
319
+ // 1. Get numbers greater than 10
320
+ // 2. Get even numbers only
321
+ // 3. Get numbers between 10 and 50
322
+ ```
323
+
324
+ **Solution:**
325
+ ```javascript
326
+ const numbers = [5, 12, 8, 130, 44, 3, 21]
327
+
328
+ // 1. Greater than 10
329
+ const greaterThan10 = numbers.filter(num => num > 10)
330
+ console.log(greaterThan10) // [12, 130, 44, 21]
331
+
332
+ // 2. Even numbers
333
+ const evens = numbers.filter(num => num % 2 === 0)
334
+ console.log(evens) // [12, 8, 130, 44]
335
+
336
+ // 3. Between 10 and 50
337
+ const between = numbers.filter(num => num >= 10 && num <= 50)
338
+ console.log(between) // [12, 44, 21]
339
+ ```
340
+
341
+ **LazyVim Tip:** Use `<C-n>` on `num` to select all occurrences and edit simultaneously.
342
+
343
+ }}}
344
+
345
+ ### Warmup 2.3: Array.find() - Search {{{
346
+
347
+ **Exercise:**
348
+ ```javascript
349
+ const users = ["ana", "carlos", "diana", "eduardo"]
350
+
351
+ // TODO:
352
+ // 1. Find first name starting with 'd'
353
+ // 2. Find first name longer than 5 characters
354
+ ```
355
+
356
+ **Solution:**
357
+ ```javascript
358
+ const users = ["ana", "carlos", "diana", "eduardo"]
359
+
360
+ // 1. Starts with 'd'
361
+ const startsWithD = users.find(name => name.startsWith('d'))
362
+ console.log(startsWithD) // "diana"
363
+
364
+ // 2. Longer than 5 characters
365
+ const longName = users.find(name => name.length > 5)
366
+ console.log(longName) // "carlos"
367
+
368
+ // Note: find() returns first match or undefined
369
+ const notFound = users.find(name => name.startsWith('z'))
370
+ console.log(notFound) // undefined
371
+ ```
372
+
373
+ **LazyVim Tip:** Use `gd` on variable name to see all usages in file.
374
+
375
+ }}}
376
+
377
+ ### Warmup 2.4: Array.includes() - Check {{{
378
+
379
+ **Exercise:**
380
+ ```javascript
381
+ const validRoles = ["admin", "editor", "viewer"]
382
+
383
+ // TODO: Check if "editor" and "superadmin" are valid roles
384
+ ```
385
+
386
+ **Solution:**
387
+ ```javascript
388
+ const validRoles = ["admin", "editor", "viewer"]
389
+
390
+ console.log(validRoles.includes("editor")) // true
391
+ console.log(validRoles.includes("superadmin")) // false
392
+
393
+ // Use case: validation
394
+ function isValidRole(role) {
395
+ return validRoles.includes(role)
396
+ }
397
+
398
+ console.log(isValidRole("admin")) // true
399
+ console.log(isValidRole("hacker")) // false
400
+ ```
401
+
402
+ }}}
403
+
404
+ }}}
405
+
406
+ ## Level 3: Array of Objects {{{
407
+
408
+ ### Warmup 3.1: Filter Objects by Property {{{
409
+
410
+ **Exercise:**
411
+ ```javascript
412
+ const products = [
413
+ { id: 1, name: "Mouse", price: 200, category: "electronics" },
414
+ { id: 2, name: "Teclado", price: 500, category: "electronics" },
415
+ { id: 3, name: "Silla", price: 1500, category: "furniture" },
416
+ { id: 4, name: "Monitor", price: 3000, category: "electronics" }
417
+ ]
418
+
419
+ // TODO:
420
+ // 1. Get all electronics
421
+ // 2. Get products under $1000
422
+ // 3. Get products with price between 500 and 2000
423
+ ```
424
+
425
+ **Solution:**
426
+ ```javascript
427
+ const products = [
428
+ { id: 1, name: "Mouse", price: 200, category: "electronics" },
429
+ { id: 2, name: "Teclado", price: 500, category: "electronics" },
430
+ { id: 3, name: "Silla", price: 1500, category: "furniture" },
431
+ { id: 4, name: "Monitor", price: 3000, category: "electronics" }
432
+ ]
433
+
434
+ // 1. All electronics
435
+ const electronics = products.filter(p => p.category === "electronics")
436
+ console.log(electronics)
437
+ // [Mouse, Teclado, Monitor]
438
+
439
+ // 2. Under $1000
440
+ const affordable = products.filter(p => p.price < 1000)
441
+ console.log(affordable)
442
+ // [Mouse, Teclado]
443
+
444
+ // 3. Between 500 and 2000
445
+ const midRange = products.filter(p => p.price >= 500 && p.price <= 2000)
446
+ console.log(midRange)
447
+ // [Teclado, Silla]
448
+ ```
449
+
450
+ **LazyVim Tip:** Use `va{` to select entire object, then `p` to paste elsewhere.
451
+
452
+ }}}
453
+
454
+ ### Warmup 3.2: Map Objects to Extract Values {{{
455
+
456
+ **Exercise:**
457
+ ```javascript
458
+ const students = [
459
+ { name: "Ana", grade: 85, passed: true },
460
+ { name: "Bruno", grade: 92, passed: true },
461
+ { name: "Carla", grade: 68, passed: false },
462
+ { name: "Diego", grade: 78, passed: true }
463
+ ]
464
+
465
+ // TODO:
466
+ // 1. Get array of just names
467
+ // 2. Get array of just grades
468
+ // 3. Get array of objects with name + grade only
469
+ ```
470
+
471
+ **Solution:**
472
+ ```javascript
473
+ const students = [
474
+ { name: "Ana", grade: 85, passed: true },
475
+ { name: "Bruno", grade: 92, passed: true },
476
+ { name: "Carla", grade: 68, passed: false },
477
+ { name: "Diego", grade: 78, passed: true }
478
+ ]
479
+
480
+ // 1. Just names
481
+ const names = students.map(s => s.name)
482
+ console.log(names)
483
+ // ["Ana", "Bruno", "Carla", "Diego"]
484
+
485
+ // 2. Just grades
486
+ const grades = students.map(s => s.grade)
487
+ console.log(grades)
488
+ // [85, 92, 68, 78]
489
+
490
+ // 3. Name + grade objects
491
+ const simplified = students.map(s => ({ name: s.name, grade: s.grade }))
492
+ console.log(simplified)
493
+ // [{ name: "Ana", grade: 85 }, ...]
494
+
495
+ // Or using destructuring:
496
+ const simplified2 = students.map(({ name, grade }) => ({ name, grade }))
497
+ ```
498
+
499
+ **LazyVim Tip:** Use `ci{` to change object content quickly.
500
+
501
+ }}}
502
+
503
+ ### Warmup 3.3: Find Object by Property {{{
504
+
505
+ **Exercise:**
506
+ ```javascript
507
+ const employees = [
508
+ { id: 101, name: "Laura", department: "Engineering" },
509
+ { id: 102, name: "Miguel", department: "Sales" },
510
+ { id: 103, name: "Sofia", department: "Engineering" },
511
+ { id: 104, name: "Pedro", department: "HR" }
512
+ ]
513
+
514
+ // TODO:
515
+ // 1. Find employee with id 103
516
+ // 2. Find first employee in Engineering
517
+ // 3. Find employee named "Pedro"
518
+ ```
519
+
520
+ **Solution:**
521
+ ```javascript
522
+ const employees = [
523
+ { id: 101, name: "Laura", department: "Engineering" },
524
+ { id: 102, name: "Miguel", department: "Sales" },
525
+ { id: 103, name: "Sofia", department: "Engineering" },
526
+ { id: 104, name: "Pedro", department: "HR" }
527
+ ]
528
+
529
+ // 1. By ID
530
+ const employee = employees.find(e => e.id === 103)
531
+ console.log(employee)
532
+ // { id: 103, name: "Sofia", department: "Engineering" }
533
+
534
+ // 2. First in Engineering
535
+ const engineer = employees.find(e => e.department === "Engineering")
536
+ console.log(engineer)
537
+ // { id: 101, name: "Laura", department: "Engineering" }
538
+
539
+ // 3. By name
540
+ const pedro = employees.find(e => e.name === "Pedro")
541
+ console.log(pedro)
542
+ // { id: 104, name: "Pedro", department: "HR" }
543
+ ```
544
+
545
+ }}}
546
+
547
+ ### Warmup 3.4: Sort Array of Objects {{{
548
+
549
+ **Exercise:**
550
+ ```javascript
551
+ const tasks = [
552
+ { title: "Fix bug", priority: 3, completed: false },
553
+ { title: "Write docs", priority: 1, completed: false },
554
+ { title: "Deploy", priority: 2, completed: true },
555
+ { title: "Review PR", priority: 3, completed: false }
556
+ ]
557
+
558
+ // TODO:
559
+ // 1. Sort by priority (lowest first)
560
+ // 2. Sort by priority (highest first)
561
+ // 3. Sort by title alphabetically
562
+ ```
563
+
564
+ **Solution:**
565
+ ```javascript
566
+ const tasks = [
567
+ { title: "Fix bug", priority: 3, completed: false },
568
+ { title: "Write docs", priority: 1, completed: false },
569
+ { title: "Deploy", priority: 2, completed: true },
570
+ { title: "Review PR", priority: 3, completed: false }
571
+ ]
572
+
573
+ // 1. Priority ascending (lowest first)
574
+ const sortedAsc = [...tasks].sort((a, b) => a.priority - b.priority)
575
+ console.log(sortedAsc.map(t => `${t.title} (${t.priority})`))
576
+ // ["Write docs (1)", "Deploy (2)", "Fix bug (3)", "Review PR (3)"]
577
+
578
+ // 2. Priority descending (highest first)
579
+ const sortedDesc = [...tasks].sort((a, b) => b.priority - a.priority)
580
+ console.log(sortedDesc.map(t => `${t.title} (${t.priority})`))
581
+ // ["Fix bug (3)", "Review PR (3)", "Deploy (2)", "Write docs (1)"]
582
+
583
+ // 3. Alphabetically by title
584
+ const sortedAlpha = [...tasks].sort((a, b) => a.title.localeCompare(b.title))
585
+ console.log(sortedAlpha.map(t => t.title))
586
+ // ["Deploy", "Fix bug", "Review PR", "Write docs"]
587
+ ```
588
+
589
+ **Note:** `[...tasks]` creates a copy because `.sort()` mutates the original array.
590
+
591
+ **LazyVim Tip:** Use `V` to select line, then `:!node` to run just that line in Node.
592
+
593
+ }}}
594
+
595
+ }}}
596
+
597
+ ## Level 4: Advanced Patterns {{{
598
+
599
+ ### Warmup 4.1: Array.reduce() - Sum & Count {{{
600
+
601
+ **Exercise:**
602
+ ```javascript
603
+ const cart = [
604
+ { product: "Mouse", price: 200, quantity: 2 },
605
+ { product: "Teclado", price: 500, quantity: 1 },
606
+ { product: "Monitor", price: 3000, quantity: 1 }
607
+ ]
608
+
609
+ // TODO:
610
+ // 1. Calculate total price (price * quantity for all items)
611
+ // 2. Count total items in cart
612
+ ```
613
+
614
+ **Solution:**
615
+ ```javascript
616
+ const cart = [
617
+ { product: "Mouse", price: 200, quantity: 2 },
618
+ { product: "Teclado", price: 500, quantity: 1 },
619
+ { product: "Monitor", price: 3000, quantity: 1 }
620
+ ]
621
+
622
+ // 1. Total price
623
+ const total = cart.reduce((sum, item) => {
624
+ return sum + (item.price * item.quantity)
625
+ }, 0)
626
+ console.log(total) // 3900 (400 + 500 + 3000)
627
+
628
+ // Shorter version:
629
+ const total2 = cart.reduce((sum, item) => sum + (item.price * item.quantity), 0)
630
+
631
+ // 2. Total items
632
+ const totalItems = cart.reduce((count, item) => count + item.quantity, 0)
633
+ console.log(totalItems) // 4 (2 + 1 + 1)
634
+ ```
635
+
636
+ **How reduce works:**
637
+ ```javascript
638
+ // reduce((accumulator, currentItem) => newAccumulator, initialValue)
639
+ // ↑ ↑ ↑ ↑
640
+ // previous current item what to starting
641
+ // result return next value
642
+ ```
643
+
644
+ }}}
645
+
646
+ ### Warmup 4.2: Group By Property {{{
647
+
648
+ **Exercise:**
649
+ ```javascript
650
+ const transactions = [
651
+ { id: 1, type: "income", amount: 5000 },
652
+ { id: 2, type: "expense", amount: 1200 },
653
+ { id: 3, type: "income", amount: 3000 },
654
+ { id: 4, type: "expense", amount: 800 },
655
+ { id: 5, type: "income", amount: 2000 }
656
+ ]
657
+
658
+ // TODO: Group transactions by type
659
+ // Result: { income: [...], expense: [...] }
660
+ ```
661
+
662
+ **Solution:**
663
+ ```javascript
664
+ const transactions = [
665
+ { id: 1, type: "income", amount: 5000 },
666
+ { id: 2, type: "expense", amount: 1200 },
667
+ { id: 3, type: "income", amount: 3000 },
668
+ { id: 4, type: "expense", amount: 800 },
669
+ { id: 5, type: "income", amount: 2000 }
670
+ ]
671
+
672
+ const grouped = transactions.reduce((acc, transaction) => {
673
+ const type = transaction.type
674
+
675
+ // Create array if doesn't exist
676
+ if (!acc[type]) {
677
+ acc[type] = []
678
+ }
679
+
680
+ // Add transaction to appropriate group
681
+ acc[type].push(transaction)
682
+
683
+ return acc
684
+ }, {})
685
+
686
+ console.log(grouped)
687
+ /*
688
+ {
689
+ income: [
690
+ { id: 1, type: "income", amount: 5000 },
691
+ { id: 3, type: "income", amount: 3000 },
692
+ { id: 5, type: "income", amount: 2000 }
693
+ ],
694
+ expense: [
695
+ { id: 2, type: "expense", amount: 1200 },
696
+ { id: 4, type: "expense", amount: 800 }
697
+ ]
698
+ }
699
+ */
700
+
701
+ // Calculate totals per group:
702
+ const totals = Object.entries(grouped).map(([type, items]) => ({
703
+ type,
704
+ total: items.reduce((sum, item) => sum + item.amount, 0)
705
+ }))
706
+ console.log(totals)
707
+ // [{ type: "income", total: 10000 }, { type: "expense", total: 2000 }]
708
+ ```
709
+
710
+ **LazyVim Tip:** Use `=i{` to auto-format the grouped object for readability.
711
+
712
+ }}}
713
+
714
+ ### Warmup 4.3: Chain Multiple Methods {{{
715
+
716
+ **Exercise:**
717
+ ```javascript
718
+ const orders = [
719
+ { id: 1, customer: "Ana", total: 500, status: "completed" },
720
+ { id: 2, customer: "Bruno", total: 1200, status: "completed" },
721
+ { id: 3, customer: "Carla", total: 300, status: "pending" },
722
+ { id: 4, customer: "Diana", total: 2000, status: "completed" },
723
+ { id: 5, customer: "Eduardo", total: 150, status: "cancelled" }
724
+ ]
725
+
726
+ // TODO: Get total revenue from completed orders over $500
727
+ ```
728
+
729
+ **Solution:**
730
+ ```javascript
731
+ const orders = [
732
+ { id: 1, customer: "Ana", total: 500, status: "completed" },
733
+ { id: 2, customer: "Bruno", total: 1200, status: "completed" },
734
+ { id: 3, customer: "Carla", total: 300, status: "pending" },
735
+ { id: 4, customer: "Diana", total: 2000, status: "completed" },
736
+ { id: 5, customer: "Eduardo", total: 150, status: "cancelled" }
737
+ ]
738
+
739
+ const revenue = orders
740
+ .filter(order => order.status === "completed") // Only completed
741
+ .filter(order => order.total > 500) // Over $500
742
+ .reduce((sum, order) => sum + order.total, 0) // Sum totals
743
+
744
+ console.log(revenue) // 3200 (1200 + 2000)
745
+
746
+ // Alternative: Single filter
747
+ const revenue2 = orders
748
+ .filter(o => o.status === "completed" && o.total > 500)
749
+ .reduce((sum, o) => sum + o.total, 0)
750
+
751
+ // Step by step visualization:
752
+ const completed = orders.filter(o => o.status === "completed")
753
+ console.log("Completed:", completed.length) // 3
754
+
755
+ const highValue = completed.filter(o => o.total > 500)
756
+ console.log("High value:", highValue.length) // 2
757
+
758
+ const total = highValue.reduce((sum, o) => sum + o.total, 0)
759
+ console.log("Total:", total) // 3200
760
+ ```
761
+
762
+ **LazyVim Tip:** Use `Vj` to select multiple lines, then `>` to indent for readability.
763
+
764
+ }}}
765
+
766
+ ### Warmup 4.4: Build Lookup Object {{{
767
+
768
+ **Exercise:**
769
+ ```javascript
770
+ const products = [
771
+ { sku: "MSE-001", name: "Mouse", price: 200 },
772
+ { sku: "KBD-002", name: "Teclado", price: 500 },
773
+ { sku: "MON-003", name: "Monitor", price: 3000 }
774
+ ]
775
+
776
+ // TODO: Create lookup object where sku is key
777
+ // Result: { "MSE-001": {...}, "KBD-002": {...}, ... }
778
+ ```
779
+
780
+ **Solution:**
781
+ ```javascript
782
+ const products = [
783
+ { sku: "MSE-001", name: "Mouse", price: 200 },
784
+ { sku: "KBD-002", name: "Teclado", price: 500 },
785
+ { sku: "MON-003", name: "Monitor", price: 3000 }
786
+ ]
787
+
788
+ // Method 1: Using reduce
789
+ const lookup = products.reduce((acc, product) => {
790
+ acc[product.sku] = product
791
+ return acc
792
+ }, {})
793
+
794
+ console.log(lookup)
795
+ /*
796
+ {
797
+ "MSE-001": { sku: "MSE-001", name: "Mouse", price: 200 },
798
+ "KBD-002": { sku: "KBD-002", name: "Teclado", price: 500 },
799
+ "MON-003": { sku: "MON-003", name: "Monitor", price: 3000 }
800
+ }
801
+ */
802
+
803
+ // Usage: Fast lookups by SKU
804
+ console.log(lookup["KBD-002"].price) // 500
805
+
806
+ // Method 2: Using Object.fromEntries (modern)
807
+ const lookup2 = Object.fromEntries(
808
+ products.map(p => [p.sku, p])
809
+ )
810
+
811
+ // Why this is useful:
812
+ // Array.find() = O(n) - has to search
813
+ // Object lookup = O(1) - instant access
814
+ ```
815
+
816
+ }}}
817
+
818
+ ### Warmup 4.5: Flatten Nested Arrays {{{
819
+
820
+ **Exercise:**
821
+ ```javascript
822
+ const teams = [
823
+ { name: "Frontend", members: ["Ana", "Bruno"] },
824
+ { name: "Backend", members: ["Carla", "Diego", "Elena"] },
825
+ { name: "DevOps", members: ["Franco"] }
826
+ ]
827
+
828
+ // TODO: Get a single array of all member names
829
+ ```
830
+
831
+ **Solution:**
832
+ ```javascript
833
+ const teams = [
834
+ { name: "Frontend", members: ["Ana", "Bruno"] },
835
+ { name: "Backend", members: ["Carla", "Diego", "Elena"] },
836
+ { name: "DevOps", members: ["Franco"] }
837
+ ]
838
+
839
+ // Method 1: flatMap (recommended)
840
+ const allMembers = teams.flatMap(team => team.members)
841
+ console.log(allMembers)
842
+ // ["Ana", "Bruno", "Carla", "Diego", "Elena", "Franco"]
843
+
844
+ // Method 2: map + flat
845
+ const allMembers2 = teams.map(team => team.members).flat()
846
+
847
+ // Method 3: reduce + concat
848
+ const allMembers3 = teams.reduce((all, team) => {
849
+ return all.concat(team.members)
850
+ }, [])
851
+
852
+ // Advanced: Include team name
853
+ const withTeams = teams.flatMap(team =>
854
+ team.members.map(member => ({
855
+ name: member,
856
+ team: team.name
857
+ }))
858
+ )
859
+ console.log(withTeams)
860
+ /*
861
+ [
862
+ { name: "Ana", team: "Frontend" },
863
+ { name: "Bruno", team: "Frontend" },
864
+ { name: "Carla", team: "Backend" },
865
+ ...
866
+ ]
867
+ */
868
+ ```
869
+
870
+ }}}
871
+
872
+ ### Warmup 4.6: Complex Transformation {{{
873
+
874
+ **Exercise:**
875
+ ```javascript
876
+ const rawData = [
877
+ { userId: 1, purchaseDate: "2024-01-15", amount: 500 },
878
+ { userId: 2, purchaseDate: "2024-01-16", amount: 1200 },
879
+ { userId: 1, purchaseDate: "2024-02-01", amount: 300 },
880
+ { userId: 3, purchaseDate: "2024-02-05", amount: 2000 },
881
+ { userId: 2, purchaseDate: "2024-02-10", amount: 800 }
882
+ ]
883
+
884
+ // TODO: Transform to:
885
+ // [
886
+ // { userId: 1, totalSpent: 800, purchases: 2 },
887
+ // { userId: 2, totalSpent: 2000, purchases: 2 },
888
+ // { userId: 3, totalSpent: 2000, purchases: 1 }
889
+ // ]
890
+ ```
891
+
892
+ **Solution:**
893
+ ```javascript
894
+ const rawData = [
895
+ { userId: 1, purchaseDate: "2024-01-15", amount: 500 },
896
+ { userId: 2, purchaseDate: "2024-01-16", amount: 1200 },
897
+ { userId: 1, purchaseDate: "2024-02-01", amount: 300 },
898
+ { userId: 3, purchaseDate: "2024-02-05", amount: 2000 },
899
+ { userId: 2, purchaseDate: "2024-02-10", amount: 800 }
900
+ ]
901
+
902
+ // Step 1: Group by userId
903
+ const grouped = rawData.reduce((acc, purchase) => {
904
+ const id = purchase.userId
905
+
906
+ if (!acc[id]) {
907
+ acc[id] = []
908
+ }
909
+
910
+ acc[id].push(purchase)
911
+ return acc
912
+ }, {})
913
+
914
+ // Step 2: Transform to summary
915
+ const summary = Object.entries(grouped).map(([userId, purchases]) => ({
916
+ userId: parseInt(userId),
917
+ totalSpent: purchases.reduce((sum, p) => sum + p.amount, 0),
918
+ purchases: purchases.length
919
+ }))
920
+
921
+ console.log(summary)
922
+ /*
923
+ [
924
+ { userId: 1, totalSpent: 800, purchases: 2 },
925
+ { userId: 2, totalSpent: 2000, purchases: 2 },
926
+ { userId: 3, totalSpent: 2000, purchases: 1 }
927
+ ]
928
+ */
929
+
930
+ // All in one chain:
931
+ const summary2 = Object.values(
932
+ rawData.reduce((acc, p) => {
933
+ if (!acc[p.userId]) {
934
+ acc[p.userId] = { userId: p.userId, totalSpent: 0, purchases: 0 }
935
+ }
936
+ acc[p.userId].totalSpent += p.amount
937
+ acc[p.userId].purchases += 1
938
+ return acc
939
+ }, {})
940
+ )
941
+ ```
942
+
943
+ **LazyVim Tip:** Use `zf` in visual mode to create custom folds for complex functions.
944
+
945
+ }}}
946
+
947
+ }}}
948
+
949
+ ## 🎯 Challenge Exercises {{{
950
+
951
+ ### Challenge 1: E-commerce Cart {{{
952
+
953
+ **Scenario:**
954
+ ```javascript
955
+ const cartItems = [
956
+ { id: 1, product: "Laptop", price: 15000, quantity: 1, discount: 0.1 },
957
+ { id: 2, product: "Mouse", price: 300, quantity: 2, discount: 0 },
958
+ { id: 3, product: "Teclado", price: 800, quantity: 1, discount: 0.15 }
959
+ ]
960
+
961
+ // TODO:
962
+ // 1. Calculate subtotal (price * quantity) for each item
963
+ // 2. Apply discount to each item
964
+ // 3. Calculate final total for entire cart
965
+ // 4. Find most expensive item (after discount)
966
+ ```
967
+
968
+ **Your turn!** Try solving before looking at solution.
969
+
970
+ <details>
971
+ <summary>Solution (click to reveal)</summary>
972
+
973
+ ```javascript
974
+ const cartItems = [
975
+ { id: 1, product: "Laptop", price: 15000, quantity: 1, discount: 0.1 },
976
+ { id: 2, product: "Mouse", price: 300, quantity: 2, discount: 0 },
977
+ { id: 3, product: "Teclado", price: 800, quantity: 1, discount: 0.15 }
978
+ ]
979
+
980
+ // 1 & 2: Add subtotal and discounted price
981
+ const withPrices = cartItems.map(item => ({
982
+ ...item,
983
+ subtotal: item.price * item.quantity,
984
+ finalPrice: item.price * item.quantity * (1 - item.discount)
985
+ }))
986
+
987
+ // 3: Total
988
+ const total = withPrices.reduce((sum, item) => sum + item.finalPrice, 0)
989
+ console.log(`Total: $${total}`) // Total: $14230
990
+
991
+ // 4: Most expensive
992
+ const mostExpensive = withPrices.reduce((max, item) =>
993
+ item.finalPrice > max.finalPrice ? item : max
994
+ )
995
+ console.log(`Most expensive: ${mostExpensive.product}`) // Laptop
996
+ ```
997
+
998
+ </details>
999
+
1000
+ }}}
1001
+
1002
+ ### Challenge 2: Student Grade Analysis {{{
1003
+
1004
+ **Scenario:**
1005
+ ```javascript
1006
+ const students = [
1007
+ { name: "Ana", scores: [85, 90, 78] },
1008
+ { name: "Bruno", scores: [92, 88, 95] },
1009
+ { name: "Carla", scores: [70, 65, 72] },
1010
+ { name: "Diego", scores: [88, 85, 90] }
1011
+ ]
1012
+
1013
+ // TODO:
1014
+ // 1. Calculate average score for each student
1015
+ // 2. Determine pass/fail (average >= 80 = pass)
1016
+ // 3. Get list of students who passed
1017
+ // 4. Calculate class average
1018
+ ```
1019
+
1020
+ **Your turn!** Try solving before looking at solution.
1021
+
1022
+ <details>
1023
+ <summary>Solution (click to reveal)</summary>
1024
+
1025
+ ```javascript
1026
+ const students = [
1027
+ { name: "Ana", scores: [85, 90, 78] },
1028
+ { name: "Bruno", scores: [92, 88, 95] },
1029
+ { name: "Carla", scores: [70, 65, 72] },
1030
+ { name: "Diego", scores: [88, 85, 90] }
1031
+ ]
1032
+
1033
+ // 1: Calculate averages
1034
+ const withAverages = students.map(student => {
1035
+ const avg = student.scores.reduce((sum, score) => sum + score, 0) / student.scores.length
1036
+ return {
1037
+ ...student,
1038
+ average: avg,
1039
+ passed: avg >= 80
1040
+ }
1041
+ })
1042
+
1043
+ // 2 & 3: Who passed?
1044
+ const passed = withAverages.filter(s => s.passed)
1045
+ console.log("Passed:", passed.map(s => s.name))
1046
+ // ["Ana", "Bruno", "Diego"]
1047
+
1048
+ // 4: Class average
1049
+ const classAvg = withAverages.reduce((sum, s) => sum + s.average, 0) / withAverages.length
1050
+ console.log(`Class average: ${classAvg.toFixed(2)}`)
1051
+ // Class average: 82.17
1052
+ ```
1053
+
1054
+ </details>
1055
+
1056
+ }}}
1057
+
1058
+ ### Challenge 3: API Response Transformation {{{
1059
+
1060
+ **Scenario:**
1061
+ ```javascript
1062
+ // Raw API response
1063
+ const apiResponse = {
1064
+ users: [
1065
+ { id: 1, username: "ana_dev", email: "ana@example.com" },
1066
+ { id: 2, username: "bruno_code", email: "bruno@example.com" }
1067
+ ],
1068
+ posts: [
1069
+ { id: 101, userId: 1, title: "First post", likes: 10 },
1070
+ { id: 102, userId: 1, title: "Second post", likes: 5 },
1071
+ { id: 103, userId: 2, title: "Bruno's post", likes: 20 }
1072
+ ]
1073
+ }
1074
+
1075
+ // TODO: Transform to:
1076
+ // [
1077
+ // {
1078
+ // username: "ana_dev",
1079
+ // postCount: 2,
1080
+ // totalLikes: 15,
1081
+ // posts: [...]
1082
+ // },
1083
+ // {
1084
+ // username: "bruno_code",
1085
+ // postCount: 1,
1086
+ // totalLikes: 20,
1087
+ // posts: [...]
1088
+ // }
1089
+ // ]
1090
+ ```
1091
+
1092
+ **Your turn!** This is a complex one - take your time.
1093
+
1094
+ <details>
1095
+ <summary>Solution (click to reveal)</summary>
1096
+
1097
+ ```javascript
1098
+ const apiResponse = {
1099
+ users: [
1100
+ { id: 1, username: "ana_dev", email: "ana@example.com" },
1101
+ { id: 2, username: "bruno_code", email: "bruno@example.com" }
1102
+ ],
1103
+ posts: [
1104
+ { id: 101, userId: 1, title: "First post", likes: 10 },
1105
+ { id: 102, userId: 1, title: "Second post", likes: 5 },
1106
+ { id: 103, userId: 2, title: "Bruno's post", likes: 20 }
1107
+ ]
1108
+ }
1109
+
1110
+ const transformed = apiResponse.users.map(user => {
1111
+ // Get posts for this user
1112
+ const userPosts = apiResponse.posts.filter(post => post.userId === user.id)
1113
+
1114
+ // Calculate stats
1115
+ const totalLikes = userPosts.reduce((sum, post) => sum + post.likes, 0)
1116
+
1117
+ return {
1118
+ username: user.username,
1119
+ postCount: userPosts.length,
1120
+ totalLikes: totalLikes,
1121
+ posts: userPosts.map(p => ({ title: p.title, likes: p.likes }))
1122
+ }
1123
+ })
1124
+
1125
+ console.log(JSON.stringify(transformed, null, 2))
1126
+ ```
1127
+
1128
+ </details>
1129
+
1130
+ }}}
1131
+
1132
+ }}}
1133
+
1134
+ ## 📚 Quick Reference {{{
1135
+
1136
+ ### Array Methods Cheat Sheet {{{
1137
+
1138
+ ```javascript
1139
+ // TRANSFORM
1140
+ .map(item => newItem) // Transform each item
1141
+
1142
+ // FILTER
1143
+ .filter(item => condition) // Keep items that match
1144
+
1145
+ // FIND
1146
+ .find(item => condition) // First match or undefined
1147
+ .findIndex(item => condition) // Index of first match or -1
1148
+
1149
+ // CHECK
1150
+ .includes(value) // Does array contain value?
1151
+ .some(item => condition) // Do ANY items match?
1152
+ .every(item => condition) // Do ALL items match?
1153
+
1154
+ // AGGREGATE
1155
+ .reduce((acc, item) => newAcc, initial) // Accumulate to single value
1156
+
1157
+ // SORT
1158
+ .sort((a, b) => a - b) // Sort numbers ascending
1159
+ .sort((a, b) => b - a) // Sort numbers descending
1160
+ .sort((a, b) => a.localeCompare(b)) // Sort strings
1161
+
1162
+ // FLATTEN
1163
+ .flat() // Flatten one level
1164
+ .flat(2) // Flatten two levels
1165
+ .flatMap(item => array) // Map + flatten
1166
+
1167
+ // OTHERS
1168
+ .slice(start, end) // Copy portion
1169
+ .concat(otherArray) // Combine arrays
1170
+ .join(separator) // Array to string
1171
+ ```
1172
+
1173
+ }}}
1174
+
1175
+ ### Object Methods Cheat Sheet {{{
1176
+
1177
+ ```javascript
1178
+ // KEYS & VALUES
1179
+ Object.keys(obj) // Array of keys
1180
+ Object.values(obj) // Array of values
1181
+ Object.entries(obj) // Array of [key, value] pairs
1182
+
1183
+ // CREATE
1184
+ Object.fromEntries(pairs) // Create object from [key, value] pairs
1185
+ Object.assign({}, obj1, obj2) // Merge objects
1186
+ { ...obj1, ...obj2 } // Spread merge
1187
+
1188
+ // CHECK
1189
+ obj.hasOwnProperty('key') // Does property exist?
1190
+ 'key' in obj // Does property exist? (includes inherited)
1191
+
1192
+ // TRANSFORM
1193
+ Object.entries(obj).map(([k, v]) => ...) // Transform to array
1194
+ Object.fromEntries( // Transform back to object
1195
+ Object.entries(obj).map(...)
1196
+ )
1197
+ ```
1198
+
1199
+ }}}
1200
+
1201
+ ### Common Patterns {{{
1202
+
1203
+ ```javascript
1204
+ // PATTERN: Filter + Map
1205
+ const result = array
1206
+ .filter(item => condition)
1207
+ .map(item => transform)
1208
+
1209
+ // PATTERN: Group by property
1210
+ const grouped = array.reduce((acc, item) => {
1211
+ const key = item.property
1212
+ if (!acc[key]) acc[key] = []
1213
+ acc[key].push(item)
1214
+ return acc
1215
+ }, {})
1216
+
1217
+ // PATTERN: Sum property
1218
+ const total = array.reduce((sum, item) => sum + item.value, 0)
1219
+
1220
+ // PATTERN: Find max/min
1221
+ const max = array.reduce((max, item) =>
1222
+ item.value > max.value ? item : max
1223
+ )
1224
+
1225
+ // PATTERN: Create lookup
1226
+ const lookup = array.reduce((acc, item) => {
1227
+ acc[item.id] = item
1228
+ return acc
1229
+ }, {})
1230
+
1231
+ // PATTERN: Unique values
1232
+ const unique = [...new Set(array)]
1233
+
1234
+ // PATTERN: Count occurrences
1235
+ const counts = array.reduce((acc, item) => {
1236
+ acc[item] = (acc[item] || 0) + 1
1237
+ return acc
1238
+ }, {})
1239
+ ```
1240
+
1241
+ }}}
1242
+
1243
+ }}}
1244
+
1245
+ ## 🎓 Next Steps {{{
1246
+
1247
+ ### Practice Recommendations {{{
1248
+
1249
+ 1. **Daily Warmup:** Do 2-3 exercises from different levels each morning
1250
+ 2. **Real Projects:** Apply these patterns to actual code you're writing
1251
+ 3. **Code Reviews:** Look for opportunities to simplify loops with these methods
1252
+ 4. **Performance:** Learn when to use forEach vs map vs reduce
1253
+ 5. **Readability:** Chain methods for clarity, but don't overdo it
1254
+
1255
+ }}}
1256
+
1257
+ ### Advanced Topics to Explore {{{
1258
+
1259
+ - **Immutability:** Why and when to avoid mutating arrays/objects
1260
+ - **Performance:** Big O notation for different operations
1261
+ - **Async Arrays:** Using Promise.all() with map
1262
+ - **Functional Programming:** Compose, pipe, curry
1263
+ - **TypeScript:** Adding types to these patterns
1264
+ - **Lodash/Ramda:** Utility libraries for advanced operations
1265
+
1266
+ }}}
1267
+
1268
+ ### Resources {{{
1269
+
1270
+ - **MDN Docs:** [Array methods](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array)
1271
+ - **Creta Lessons:** Review "Enunciados" for OOP patterns with arrays
1272
+ - **Practice:** [JavaScript30](https://javascript30.com/) challenges
1273
+ - **Reference:** Keep this file open in LazyVim while coding!
1274
+
1275
+ }}}
1276
+
1277
+ }}}
1278
+
1279
+ ---
1280
+
1281
+ **Pro Tip:** Keep this file in your `.config/nvim` folder or workspace root for quick reference while coding. Use `<leader>ff` in LazyVim to fuzzy find and open it instantly! 🚀