Skip to content

Commit e13ba28

Browse files
authored
Merge pull request #36 from marcode24/2024-20
✨ Add challenge-20 solution
2 parents 4b1dd1c + 995f547 commit e13ba28

File tree

4 files changed

+399
-19
lines changed

4 files changed

+399
-19
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,251 @@
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. 🎉
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
/* eslint-disable no-bitwise */
2+
/* eslint-disable no-restricted-syntax */
3+
function fixGiftList(received, expected) {
4+
const counts = {};
5+
6+
for (const gift of received) counts[gift] = ~~counts[gift] + 1;
7+
for (const gift of expected) counts[gift] = ~~counts[gift] - 1;
8+
9+
const missing = {};
10+
const extra = {};
11+
for (const [gift, count] of Object.entries(counts)) {
12+
if (count > 0) extra[gift] = count;
13+
else if (count < 0) missing[gift] = -count;
14+
}
15+
16+
return { missing, extra };
17+
}
18+
19+
module.exports = fixGiftList;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
const fixGiftList = require('./index');
2+
3+
describe('20 => Encuentra-los-regalos-faltantes-y-duplicados', () => {
4+
const TEST_CASES = [
5+
{
6+
input: [
7+
['puzzle', 'car'],
8+
['puzzle', 'car', 'ball'],
9+
],
10+
output: {
11+
missing: {
12+
ball: 1,
13+
},
14+
extra: {},
15+
},
16+
},
17+
{
18+
input: [
19+
['car', 'puzzle', 'car'],
20+
['puzzle', 'car', 'doll'],
21+
],
22+
output: {
23+
missing: {
24+
doll: 1,
25+
},
26+
extra: {
27+
car: 1,
28+
},
29+
},
30+
},
31+
{
32+
input: [
33+
['train', 'book', 'kite'],
34+
['train', 'kite', 'book', 'kite'],
35+
],
36+
output: {
37+
missing: {
38+
kite: 1,
39+
},
40+
extra: {},
41+
},
42+
},
43+
{
44+
input: [
45+
['bear', 'car'],
46+
['bear', 'car', 'car'],
47+
],
48+
output: {
49+
missing: {
50+
car: 1,
51+
},
52+
extra: {},
53+
},
54+
},
55+
{
56+
input: [[], ['bear', 'car', 'car']],
57+
output: {
58+
missing: {
59+
bear: 1,
60+
car: 2,
61+
},
62+
extra: {},
63+
},
64+
},
65+
{
66+
input: [
67+
['puzzle', 'puzzle', 'car'],
68+
['puzzle', 'car'],
69+
],
70+
output: {
71+
missing: {},
72+
extra: {
73+
puzzle: 1,
74+
},
75+
},
76+
},
77+
{
78+
input: [['car'], ['car', 'puzzle', 'ball']],
79+
output: {
80+
missing: {
81+
puzzle: 1,
82+
ball: 1,
83+
},
84+
extra: {},
85+
},
86+
},
87+
{
88+
input: [
89+
['bear', 'bear', 'car'],
90+
['bear', 'bear', 'car'],
91+
],
92+
output: {
93+
missing: {},
94+
extra: {},
95+
},
96+
},
97+
];
98+
99+
it('should return an object', () => {
100+
const testCase = TEST_CASES[0];
101+
const received = fixGiftList(...testCase.input);
102+
expect(received).toEqual(expect.any(Object));
103+
});
104+
105+
it.each(TEST_CASES)('should return the correct object', (testCase) => {
106+
const received = fixGiftList(...testCase.input);
107+
expect(received).toEqual(testCase.output);
108+
});
109+
});

0 commit comments

Comments
 (0)