|
| 1 | +# Reto 20: Encuentra-los-regalos-faltantes-y-duplicados |
| 2 | + |
| 3 | +**Santa Claus** 🎅 está revisando la lista de regalos que debe entregar esta Navidad. Sin embargo, **algunos regalos faltan, otros están duplicados, y algunos tienen cantidades incorrectas.** Necesita tu ayuda para resolver el problema. |
| 4 | + |
| 5 | +Recibirás dos arrays: |
| 6 | + |
| 7 | +- `received`: Lista con los regalos que Santa tiene actualmente. |
| 8 | +- `expected`: Lista con los regalos que Santa debería tener. |
| 9 | + |
| 10 | +Tu tarea es escribir una función que, dado received y expected, devuelva un objeto con dos propiedades: |
| 11 | + |
| 12 | +- `missing`: Un objeto donde las claves son los nombres de los regalos faltantes y los valores son las cantidades que faltan. |
| 13 | +- `extra`: Un objeto donde las claves son los nombres de los regalos extra o duplicados y los valores son las cantidades que sobran. |
| 14 | + |
| 15 | +Ten en cuenta que: |
| 16 | + |
| 17 | +- Los regalos pueden repetirse en ambas listas. |
| 18 | +- Las listas de regalos están desordenadas. |
| 19 | +- Si no hay regalos que falten o sobren, las propiedades correspondientes (`missing o extra`) deben ser objetos vacíos. |
| 20 | + |
| 21 | +```js |
| 22 | +fixGiftList(['puzzle', 'car', 'doll', 'car'], ['car', 'puzzle', 'doll', 'ball']) |
| 23 | +// Devuelve: |
| 24 | +// { |
| 25 | +// missing: { ball: 1 }, |
| 26 | +// extra: { car: 1 } |
| 27 | +// } |
| 28 | + |
| 29 | +fixGiftList( |
| 30 | + ['book', 'train', 'kite', 'train'], |
| 31 | + ['train', 'book', 'kite', 'ball', 'kite'] |
| 32 | +) |
| 33 | +// Devuelve: |
| 34 | +// { |
| 35 | +// missing: { ball: 1, kite: 1 }, |
| 36 | +// extra: { train: 1 } |
| 37 | +// } |
| 38 | + |
| 39 | +fixGiftList( |
| 40 | + ['bear', 'bear', 'car'], |
| 41 | + ['bear', 'car', 'puzzle', 'bear', 'car', 'car'] |
| 42 | +) |
| 43 | +// Devuelve: |
| 44 | +// { |
| 45 | +// missing: { puzzle: 1, car: 2 }, |
| 46 | +// extra: {} |
| 47 | +// } |
| 48 | + |
| 49 | +fixGiftList(['bear', 'bear', 'car'], ['car', 'bear', 'bear']) |
| 50 | +// Devuelve: |
| 51 | +// { |
| 52 | +// missing: {}, |
| 53 | +// extra: {} |
| 54 | +// } |
| 55 | +``` |
| 56 | + |
| 57 | +## Mi solución explicada |
| 58 | + |
| 59 | +```js |
| 60 | +function fixGiftList(received, expected) { |
| 61 | + const counts = {}; |
| 62 | + |
| 63 | + for (const gift of received) counts[gift] = ~~counts[gift] + 1; |
| 64 | + for (const gift of expected) counts[gift] = ~~counts[gift] - 1; |
| 65 | + |
| 66 | + const missing = {}; |
| 67 | + const extra = {}; |
| 68 | + for (const [gift, count] of Object.entries(counts)) { |
| 69 | + if (count > 0) extra[gift] = count; |
| 70 | + else if (count < 0) missing[gift] = -count; |
| 71 | + } |
| 72 | + |
| 73 | + return { missing, extra }; |
| 74 | +} |
| 75 | + |
| 76 | +module.exports = fixGiftList; |
| 77 | +``` |
| 78 | + |
| 79 | +Para resolver este reto, hay que tener en cuenta que necesitamos comparar dos listas de regalos: `received` y `expected`. Para ello, vamos a recorrer ambas listas y vamos a ir contando cuántas veces aparece cada regalo en cada una de ellas. |
| 80 | + |
| 81 | +Para llevar la cuenta de los regalos, vamos a utilizar un objeto llamado `counts`. Este objeto va a tener como claves los nombres de los regalos y como valores la cantidad de veces que aparece cada regalo en la lista. |
| 82 | + |
| 83 | +Como no sabemos si un regalo se repite en ambas listas, vamos a recorrer la lista `received` y vamos a incrementar en 1 la cantidad de veces que aparece cada regalo en el objeto `counts`. Luego, vamos a recorrer la lista `expected` y vamos a decrementar en 1 la cantidad de veces que aparece cada regalo en el objeto `counts`. De esta forma, si un regalo aparece en ambas listas, la cantidad de veces que aparece en el objeto `counts` será 0. Si un regalo aparece más veces en `received` que en `expected`, la cantidad será positiva. Si un regalo aparece más veces en `expected` que en `received`, la cantidad será negativa. Si un regalo no aparece en ninguna de las listas, la cantidad será 0. |
| 84 | + |
| 85 | +Una vez que tenemos el objeto `counts` con la cantidad de veces que aparece cada regalo en ambas listas, vamos a recorrer este objeto y vamos a crear dos objetos: `missing` y `extra`. En el objeto `missing` vamos a guardar los regalos que faltan y en el objeto `extra` vamos a guardar los regalos que sobran. Para ello, vamos a recorrer el objeto `counts` y vamos a verificar si la cantidad de veces que aparece un regalo es mayor que 0. Si es así, significa que ese regalo sobra y lo agregamos al objeto `extra`. Si la cantidad es menor que 0, significa que ese regalo falta y lo agregamos al objeto `missing`. |
| 86 | + |
| 87 | +Finalmente, devolvemos un objeto con las propiedades `missing` y `extra`, que contienen los regalos que faltan y sobran, respectivamente. |
| 88 | + |
| 89 | +**Veamos con un ejemplo cómo funciona el código:** |
| 90 | + |
| 91 | +Supongamos que recibimos las listas `received` y `expected` siguientes: |
| 92 | + |
| 93 | +```js |
| 94 | +const received = ['car', 'puzzle', 'car']; |
| 95 | +const expected = ['puzzle', 'car', 'doll']; |
| 96 | +``` |
| 97 | + |
| 98 | +Utilizaremos un ciclo `for...of` para recorrer la lista `received` y vamos a incrementar en 1 la cantidad de veces que aparece cada regalo en el objeto `counts`. |
| 99 | + |
| 100 | +Recorremos la lista `received` y como esta lista tiene 3 elementos, el ciclo se ejecutará 3 veces. En la primera iteración, el regalo es `'car'`. Como el objeto `counts` está vacío, la cantidad de veces que aparece el regalo `'car'` es `undefined`. Al utilizar el operador `~~` para convertir el valor a un número entero, obtenemos `0`. Luego, incrementamos en 1 la cantidad de veces que aparece el regalo `'car'` en el objeto `counts`. Ahora, el objeto `counts` es `{ car: 1 }`. |
| 101 | + |
| 102 | +```js |
| 103 | +// counts[gift] = ~~counts[gift] + 1; |
| 104 | +// counts['car'] = ~~counts['car'] + 1; |
| 105 | +// counts['car'] = ~~undefined + 1; |
| 106 | +// counts['car'] = 0 + 1; |
| 107 | +counts['car'] = 1; |
| 108 | + |
| 109 | +const counts = { car: 1 }; |
| 110 | +``` |
| 111 | + |
| 112 | +En la segunda iteración tenemos el regalo `'puzzle'`. Al igual que en la iteración anterior, la cantidad de veces que aparece el regalo `'puzzle'` es `undefined`. Al convertir este valor a un número entero, obtenemos `0`. Luego, incrementamos en 1 la cantidad de veces que aparece el regalo `'puzzle'` en el objeto `counts`. Ahora, el objeto `counts` es `{ car: 1, puzzle: 1 }`. |
| 113 | + |
| 114 | +```js |
| 115 | +// counts[gift] = ~~counts[gift] + 1; |
| 116 | +// counts['puzzle'] = ~~counts['puzzle'] + 1; |
| 117 | +// counts['puzzle'] = ~~undefined + 1; |
| 118 | +// counts['puzzle'] = 0 + 1; |
| 119 | +counts['puzzle'] = 1; |
| 120 | + |
| 121 | +const counts = { car: 1, puzzle: 1 }; |
| 122 | +``` |
| 123 | + |
| 124 | +En la tercera y última iteración, el regalo es `'car'`. La cantidad de veces que aparece el regalo `'car'` en el objeto `counts` es `1`. Al incrementar en 1 esta cantidad, obtenemos `2`. Ahora, el objeto `counts` es `{ car: 2, puzzle: 1 }`. |
| 125 | + |
| 126 | +```js |
| 127 | +// counts[gift] = ~~counts[gift] + 1; |
| 128 | +// counts['car'] = ~~counts['car'] + 1; |
| 129 | +// counts['car'] = ~~1 + 1; |
| 130 | +// counts['car'] = 1 + 1; |
| 131 | +counts['car'] = 2; |
| 132 | + |
| 133 | +const counts = { car: 2, puzzle: 1 }; |
| 134 | +``` |
| 135 | + |
| 136 | +Luego, recorremos la lista `expected` y vamos a decrementar en 1 la cantidad de veces que aparece cada regalo en el objeto `counts`. |
| 137 | + |
| 138 | +Recorremos la lista `expected` y como esta lista tiene 3 elementos, el ciclo se ejecutará 3 veces. En la primera iteración, el regalo es `'puzzle'`. La cantidad de veces que aparece el regalo `'puzzle'` en el objeto `counts` es `1`. Al decrementar en 1 esta cantidad, obtenemos `0`. Ahora, el objeto `counts` es `{ car: 2, puzzle: 0 }`. |
| 139 | + |
| 140 | +```js |
| 141 | +// counts[gift] = ~~counts[gift] - 1; |
| 142 | +// counts['puzzle'] = ~~counts['puzzle'] - 1; |
| 143 | +// counts['puzzle'] = ~~1 - 1; |
| 144 | +// counts['puzzle'] = 1 - 1; |
| 145 | +counts['puzzle'] = 0; |
| 146 | + |
| 147 | +const counts = { car: 2, puzzle: 0 }; |
| 148 | +``` |
| 149 | + |
| 150 | +En la segunda iteración tenemos el regalo `'car'`. La cantidad de veces que aparece el regalo `'car'` en el objeto `counts` es `2`. Al decrementar en 1 esta cantidad, obtenemos `1`. Ahora, el objeto `counts` es `{ car: 1, puzzle: 0 }`. |
| 151 | + |
| 152 | +```js |
| 153 | +// counts[gift] = ~~counts[gift] - 1; |
| 154 | +// counts['car'] = ~~counts['car'] - 1; |
| 155 | +// counts['car'] = ~~2 - 1; |
| 156 | +// counts['car'] = 2 - 1; |
| 157 | +counts['car'] = 1; |
| 158 | + |
| 159 | +const counts = { car: 1, puzzle: 0 }; |
| 160 | +``` |
| 161 | + |
| 162 | +En la tercera y última iteración, el regalo es `'doll'`. La cantidad de veces que aparece el regalo `'doll'` en el objeto `counts` es `undefined`. Al convertir este valor a un número entero, obtenemos `0`. Al decrementar en 1 esta cantidad, obtenemos `-1`. Ahora, el objeto `counts` es `{ car: 1, puzzle: 0, doll: -1 }`. |
| 163 | + |
| 164 | +```js |
| 165 | +// counts[gift] = ~~counts[gift] - 1; |
| 166 | +// counts['doll'] = ~~counts['doll'] - 1; |
| 167 | +// counts['doll'] = ~~undefined - 1; |
| 168 | +// counts['doll'] = 0 - 1; |
| 169 | +counts['doll'] = -1; |
| 170 | + |
| 171 | +const counts = { car: 1, puzzle: 0, doll: -1 }; |
| 172 | +``` |
| 173 | + |
| 174 | +Una vez que tenemos el objeto `counts` con la cantidad de veces que aparece cada regalo en ambas listas, vamos a recorrer este objeto y vamos a crear dos objetos: `missing` y `extra`. |
| 175 | + |
| 176 | +Nuevamente, utilizaremos un ciclo `for...of` para recorrer el objeto `counts`. Aquí utilizaremos el método `Object.entries()` para obtener un array con las claves y valores del objeto `counts`. Luego, recorreremos este array con un ciclo `for...of` y vamos a verificar si la cantidad de veces que aparece un regalo es mayor que 0. Si es así, significa que ese regalo sobra y lo agregamos al objeto `extra`. Si la cantidad es menor que 0, significa que ese regalo falta y lo agregamos al objeto `missing`. |
| 177 | + |
| 178 | +Entonces para el objeto `counts` que tenemos, el array que obtenemos con `Object.entries(counts)` es el siguiente: |
| 179 | + |
| 180 | +```js |
| 181 | +const entries = [ |
| 182 | + ['car', 1], |
| 183 | + ['puzzle', 0], |
| 184 | + ['doll', -1] |
| 185 | +]; |
| 186 | +``` |
| 187 | + |
| 188 | +En la primera iteración, la clave es `'car'` y el valor es `1`. Como el valor es mayor que 0, agregamos el regalo `'car'` al objeto `extra` con la cantidad `1`. |
| 189 | + |
| 190 | +```js |
| 191 | +gift = 'car'; |
| 192 | +count = 1; |
| 193 | + |
| 194 | +// if (count > 0) extra[gift] = count; |
| 195 | +// if (1 > 0) extra['car'] = 1; |
| 196 | +// if (true) extra['car'] = 1; |
| 197 | +extra['car'] = 1; |
| 198 | + |
| 199 | +const extra = { car: 1 }; |
| 200 | +const missing = {}; |
| 201 | +``` |
| 202 | + |
| 203 | +En la segunda iteración, la clave es `'puzzle'` y el valor es `0`. Como el valor es igual a 0, no hacemos nada. |
| 204 | + |
| 205 | +```js |
| 206 | +gift = 'puzzle'; |
| 207 | +count = 0; |
| 208 | + |
| 209 | +// if (count > 0) extra[gift] = count; |
| 210 | +// if (0 > 0) extra['puzzle'] = 0; |
| 211 | +// if (false) extra['puzzle'] = 0; (no se ejecuta) |
| 212 | + |
| 213 | +// else if (count < 0) missing[gift] = -count; |
| 214 | +// else if (0 < 0) missing['puzzle'] = 0; |
| 215 | +// else if (false) missing['puzzle'] = 0; (no se ejecuta) |
| 216 | + |
| 217 | +const extra = { car: 1 }; |
| 218 | +const missing = {}; |
| 219 | +``` |
| 220 | + |
| 221 | +En la tercera y última iteración, la clave es `'doll'` y el valor es `-1`. Como el valor es menor que 0, agregamos el regalo `'doll'` al objeto `missing` con la cantidad `1`. |
| 222 | + |
| 223 | +```js |
| 224 | +gift = 'doll'; |
| 225 | +count = -1; |
| 226 | + |
| 227 | +// if (count > 0) extra[gift] = count; |
| 228 | +// if (-1 > 0) extra['doll'] = -1; |
| 229 | +// if (false) extra['doll'] = -1; (no se ejecuta) |
| 230 | + |
| 231 | +// else if (count < 0) missing[gift] = -count; |
| 232 | +// else if (-1 < 0) missing['doll'] = -(-1); |
| 233 | +// else if (true) missing['doll'] = 1; |
| 234 | +missing['doll'] = 1; |
| 235 | + |
| 236 | +const extra = { car: 1 }; |
| 237 | +const missing = { doll: 1 }; |
| 238 | +``` |
| 239 | + |
| 240 | +Finalmente, devolvemos un objeto con las propiedades `missing` y `extra`, que contienen los regalos que faltan y sobran, respectivamente. |
| 241 | + |
| 242 | +```js |
| 243 | +{ |
| 244 | + missing: { doll: 1 }, |
| 245 | + extra: { car: 1 } |
| 246 | +} |
| 247 | +``` |
| 248 | + |
| 249 | +En este caso, el regalo `'doll'` falta y el regalo `'car'` sobra. |
| 250 | + |
| 251 | +Y con esto hemos terminado de resolver el reto. 🎉 |
0 commit comments