diff --git a/2024/05-emparejando-botas/README.md b/2024/05-emparejando-botas/README.md new file mode 100644 index 0000000..531c70b --- /dev/null +++ b/2024/05-emparejando-botas/README.md @@ -0,0 +1,144 @@ +# Reto 05: Emparejando-botas + +**Los elfos 🧝🧝‍♂️ de Santa Claus** han encontrado un montón de botas mágicas desordenadas en el taller. Cada bota se describe por dos valores: + +- type indica si es una bota izquierda (I) o derecha (R). +- size indica el tamaño de la bota. + +Tu tarea es ayudar a los elfos a emparejar todas las botas del mismo tamaño que tengan izquierda y derecha. Para ello, debes devolver una lista con los pares disponibles después de emparejar las botas. + +¡Ten en cuenta que **puedes tener más de una zapatilla emparejada del mismo tamaño!** + +```js +const shoes = [ + { type: 'I', size: 38 }, + { type: 'R', size: 38 }, + { type: 'R', size: 42 }, + { type: 'I', size: 41 }, + { type: 'I', size: 42 } +] + +organizeShoes(shoes) +// [38, 42] + +const shoes2 = [ + { type: 'I', size: 38 }, + { type: 'R', size: 38 }, + { type: 'I', size: 38 }, + { type: 'I', size: 38 }, + { type: 'R', size: 38 } +] +// [38, 38] + +const shoes3 = [ + { type: 'I', size: 38 }, + { type: 'R', size: 36 }, + { type: 'R', size: 42 }, + { type: 'I', size: 41 }, + { type: 'I', size: 43 } +] + +organizeShoes(shoes3) +// [] +``` + +## Mi solución explicada + +```js +function organizeShoes(shoes) { + const sizeCount = new Map(); + + for (const { type, size } of shoes) { + const counts = sizeCount.get(size) || { I: 0, R: 0 }; + counts[type]++; + sizeCount.set(size, counts); + } + + return Array.from(sizeCount.entries()).flatMap(([size, { I, R }]) => + Array(Math.min(I, R)).fill(size), + ); +} +``` + +Para resolver este problema, primero creamos un mapa `sizeCount` para almacenar el recuento de botas de cada tamaño. Esto nos permitirá contar cuántas botas izquierdas y derechas hay para cada tamaño. + +```js +const sizeCount = new Map(); +``` + +Luego, recorremos todas las botas y actualizamos el recuento de botas de cada tamaño en el mapa `sizeCount`. + +```js +for (const { type, size } of shoes) { + const counts = sizeCount.get(size) || { I: 0, R: 0 }; + counts[type]++; + sizeCount.set(size, counts); +} +``` + +Denotamos el recuento de botas izquierdas y derechas para cada tamaño con un objeto `{ I: 0, R: 0 }`. Luego, incrementamos el recuento correspondiente según el tipo de bota. Finalmente, actualizamos el recuento en el mapa `sizeCount`. + +Si nuestra entrada es la siguiente: + +```js +const shoes = [ + { type: 'I', size: 38 }, + { type: 'R', size: 38 }, + { type: 'R', size: 42 }, + { type: 'I', size: 41 }, + { type: 'I', size: 42 } +]; +``` + +El mapa `sizeCount` se verá así: + +```js +Map { + 38 => { I: 1, R: 1 }, + 42 => { I: 1, R: 1 }, + 41 => { I: 1, R: 0 } +} +``` + +Finalmente, devolvemos un array de pares de botas emparejadas. Para cada entrada en el mapa `sizeCount`, creamos un array de tamaño igual al mínimo de botas izquierdas y derechas para ese tamaño. Luego, llenamos el array con el tamaño de la bota y lo aplanamos. + +```js +return Array.from(sizeCount.entries()).flatMap(([size, { I, R }]) => + Array(Math.min(I, R)).fill(size), +); +``` + +Desmenuzando el código, tenemos que `sizeCount.entries()` nos devolveria lo siguiente: + +```js +[ + [38, { I: 1, R: 1 }], + [42, { I: 1, R: 1 }], + [41, { I: 1, R: 0 }] +] +``` + +Pasandolo por `flatMap`, tenemos que son 3 iteraciones. Para la primera iteración, tenemos: + +```js +size = 38 +{ I: 1, R: 1 } +``` + +Por lo que `Math.min(I, R)` nos devolvería `1`, y `Array(1).fill(size)` nos devolvería `[38]`. Para la segunda iteración, tenemos: + +```js +size = 42 +{ I: 1, R: 1 } +``` + +Por lo que `Math.min(I, R)` nos devolvería `1`, y `Array(1).fill(size)` nos devolvería `[42]`. Para la tercera iteración, tenemos: + +```js +size = 41 +{ I: 1, R: 0 } +``` + +Por lo que `Math.min(I, R)` nos devolvería `0`, y `Array(0).fill(size)` nos devolvería `[]`. + +Fuera de `flatMap`, tenemos `[ [38], [42], [] ]`. Al aplanar el array, obtenemos `[38, 42]`, que es el resultado correcto. diff --git a/2024/05-emparejando-botas/index.js b/2024/05-emparejando-botas/index.js new file mode 100644 index 0000000..bd83402 --- /dev/null +++ b/2024/05-emparejando-botas/index.js @@ -0,0 +1,18 @@ +/* eslint-disable function-paren-newline */ +/* eslint-disable implicit-arrow-linebreak */ +/* eslint-disable no-restricted-syntax */ +function organizeShoes(shoes) { + const sizeCount = new Map(); + + for (const { type, size } of shoes) { + const counts = sizeCount.get(size) || { I: 0, R: 0 }; + counts[type]++; + sizeCount.set(size, counts); + } + + return Array.from(sizeCount.entries()).flatMap(([size, { I, R }]) => + Array(Math.min(I, R)).fill(size), + ); +} + +module.exports = organizeShoes; diff --git a/2024/05-emparejando-botas/index.test.js b/2024/05-emparejando-botas/index.test.js new file mode 100644 index 0000000..3968e90 --- /dev/null +++ b/2024/05-emparejando-botas/index.test.js @@ -0,0 +1,63 @@ +const organizeShoes = require('./index'); + +describe('05 => Emparejando-botas', () => { + const testCases = [ + { + input: [ + { type: 'I', size: 38 }, + { type: 'R', size: 38 }, + { type: 'R', size: 42 }, + { type: 'I', size: 41 }, + { type: 'I', size: 42 }, + ], + output: [38, 42], + }, + { + input: [ + { type: 'I', size: 38 }, + { type: 'R', size: 38 }, + { type: 'I', size: 38 }, + { type: 'I', size: 38 }, + { type: 'R', size: 38 }, + ], + output: [38, 38], + }, + { + input: [ + { type: 'I', size: 38 }, + { type: 'R', size: 36 }, + { type: 'R', size: 42 }, + { type: 'I', size: 41 }, + { type: 'I', size: 42 }, + ], + output: [42], + }, + { + input: [ + { type: 'I', size: 40 }, + { type: 'R', size: 40 }, + { type: 'I', size: 40 }, + { type: 'R', size: 40 }, + ], + output: [40, 40], + }, + { + input: [ + { type: 'I', size: 39 }, + { type: 'R', size: 39 }, + { type: 'R', size: 39 }, + ], + output: [39], + }, + ]; + + it('should return an array', () => { + const result = organizeShoes([]); + expect(result).toBeInstanceOf(Array); + }); + + it.each(testCases)('should return $output', ({ input, output }) => { + const result = organizeShoes(input); + expect(result).toEqual(output); + }); +}); diff --git a/README.md b/README.md index ea235e9..20af784 100644 --- a/README.md +++ b/README.md @@ -63,6 +63,7 @@ npm run test 'year'/'challenge'/index.test.js | 02 | [🖼️ Enmarcando nombres](https://adventjs.dev/es/challenges/2024/2) | 🟢 | [here](./2024/02-enmarcando-nombres/index.js) | ⭐⭐⭐⭐⭐ | | 03 | [🏗️ Organizando el inventario](https://adventjs.dev/es/challenges/2024/3) | 🟢 | [here](./2024/03-organizando-el-inventario/index.js) | ⭐⭐⭐⭐⭐ | | 04 | [🎄 Decorando el árbol de Navidad](https://adventjs.dev/es/challenges/2024/4) | 🟡 | [here](./2024/04-decorando-el-arbol-de-navidad/index.js) | ⭐⭐⭐⭐⭐ | +| 05 | [👢 Emparejando botas](https://adventjs.dev/es/challenges/2024/5) | 🟢 | [here](./2024/05-emparejando-botas/index.js) | ⭐⭐⭐⭐⭐ | Difficulties legend: 🟢 Easy 🟡 Medium 🔴 Hard