Skip to content

Commit f24b553

Browse files
authored
Merge pull request #33 from marcode24/2024-15
✨ Add challenge-15 solution
2 parents 61642b9 + 67ee7a8 commit f24b553

File tree

4 files changed

+523
-0
lines changed

4 files changed

+523
-0
lines changed

2024/15-dibujando-tablas/README.md

+395
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,395 @@
1+
# Reto 15: Dibujando-tablas
2+
3+
**Al Polo Norte ha llegado ChatGPT** y el elfo Sam Elfman está trabajando en una aplicación de administración de regalos y niños.
4+
5+
Para mejorar la presentación, quiere crear una función drawTable que reciba un array de objetos y lo convierta en una tabla de texto.
6+
7+
La tabla dibujada debe representar los datos del objeto de la siguiente manera:
8+
9+
- Tiene una cabecera con el nombre de la columna.
10+
- El nombre de la columna pone la primera letra en mayúscula.
11+
- Cada fila debe contener los valores de los objetos en el orden correspondiente.
12+
- Cada valor debe estar alineado a la izquierda.
13+
- Los campos dejan siempre un espacio a la izquierda.
14+
- Los campos dejan a la derecha el espacio necesario para alinear la caja.
15+
16+
Mira el ejemplo para ver cómo debes dibujar la tabla:
17+
18+
```js
19+
drawTable([
20+
{ name: 'Alice', city: 'London' },
21+
{ name: 'Bob', city: 'Paris' },
22+
{ name: 'Charlie', city: 'New York' }
23+
])
24+
// +---------+-----------+
25+
// | Name | City |
26+
// +---------+-----------+
27+
// | Alice | London |
28+
// | Bob | Paris |
29+
// | Charlie | New York |
30+
// +---------+-----------+
31+
32+
drawTable([
33+
{ gift: 'Doll', quantity: 10 },
34+
{ gift: 'Book', quantity: 5 },
35+
{ gift: 'Music CD', quantity: 1 }
36+
])
37+
// +----------+----------+
38+
// | Gift | Quantity |
39+
// +----------+----------+
40+
// | Doll | 10 |
41+
// | Book | 5 |
42+
// | Music CD | 1 |
43+
// +----------+----------+
44+
```
45+
46+
## Mi solución explicada
47+
48+
```js
49+
function drawTable(data) {
50+
const headers = Object.keys(data[0]);
51+
52+
const columnWidths = headers.map((header) =>
53+
Math.max(header.length, ...data.map((row) => `${row[header]}`.length)),
54+
);
55+
56+
const separator = `+${columnWidths
57+
.map((width) => '-'.repeat(width + 2))
58+
.join('+')}+`;
59+
60+
const headerRowFormatted = `| ${headers
61+
.map((header, i) => {
62+
const headerFormatted = header.charAt(0).toUpperCase() + header.slice(1);
63+
return headerFormatted.padEnd(columnWidths[i]);
64+
})
65+
.join(' | ')} |`;
66+
67+
const rows = data.map(
68+
(row) =>
69+
`| ${headers
70+
.map((key, i) => `${row[key]}`.padEnd(columnWidths[i]))
71+
.join(' | ')} |`,
72+
);
73+
74+
return [separator, headerRowFormatted, separator, ...rows, separator].join(
75+
'\n',
76+
);
77+
}
78+
```
79+
80+
Para poder resolver este reto, hay que tener bien presentes los 6 puntos que se mencionan en la descripción del reto.
81+
82+
- Para el primer punto, nos dice que `Tiene una cabecera con el nombre de la columna`. Para esto, necesitamos obtener los nombres de las columnas, que son las claves de los objetos en el array de objetos que recibimos como argumento. Para obtener estas claves, usamos `Object.keys(data[0])`.
83+
84+
- Para el segundo punto, nos dice que `El nombre de la columna pone la primera letra en mayúscula`. Para esto, necesitamos convertir la primera letra de cada nombre de columna a mayúscula. Para hacer esto, usamos el método `map` para recorrer cada nombre de columna y aplicar la transformación necesaria. Usamos `header.charAt(0).toUpperCase() + header.slice(1)` para convertir la primera letra a mayúscula.
85+
86+
- Para el tercer punto, nos dice que `Cada fila debe contener los valores de los objetos en el orden correspondiente`. Para esto, necesitamos recorrer cada objeto en el array de objetos y obtener los valores correspondientes a cada columna. Usamos el método `map` para recorrer cada objeto y obtener los valores correspondientes a cada columna. Usamos `row[key]` para obtener el valor correspondiente a la columna.
87+
88+
- Para el cuarto punto, nos dice que `Cada valor debe estar alineado a la izquierda`. Para esto, necesitamos alinear cada valor a la izquierda. Usamos el método `padEnd` para alinear cada valor a la izquierda. Usamos `padEnd(columnWidths[i])` para alinear cada valor a la izquierda. El ancho de la columna lo obtenemos previamente en el array `columnWidths`.
89+
90+
- Para el quinto punto, nos dice que `Los campos dejan siempre un espacio a la izquierda`. Para esto, necesitamos dejar un espacio a la izquierda de cada valor. Usamos el espacio en blanco `' '` antes de cada valor. Usamos `' | '` para dejar un espacio a la izquierda de cada valor.
91+
92+
- Para el sexto punto, nos dice que `Los campos dejan a la derecha el espacio necesario para alinear la caja`. Para esto, necesitamos dejar el espacio necesario a la derecha de cada valor. Usamos el método `padEnd` para dejar el espacio necesario a la derecha de cada valor. Usamos `padEnd(columnWidths[i])` para dejar el espacio necesario a la derecha. El ancho de la columna lo obtenemos previamente en el array `columnWidths`.
93+
94+
Una vez que analizamos los 6 puntos, podemos ver que la solución propuesta cumple con todos los requisitos del reto.
95+
96+
**Veamos con un ejemplo cómo funciona el código:**
97+
98+
Supongamos que tenemos la siguiente entrada, donde tenemos un array de objetos con los nombres y ciudades de algunas personas.
99+
100+
```js
101+
drawTable([
102+
{ name: 'Alice', city: 'London' },
103+
{ name: 'Bob', city: 'Paris' },
104+
{ name: 'Charlie', city: 'New York' }
105+
])
106+
```
107+
108+
Primero, necesitamos obtener los nombres de las columnas, que son las claves de los objetos en el array de objetos. Utilizaremos `Object.keys(data[0])` para obtener los nombres de las columnas. Lo que hace es devolver un array con las claves de los objetos. En este caso, obtendremos `['name', 'city']`.
109+
110+
```js
111+
// const headers = Object.keys(data[0]);
112+
// const headers = Object.keys({ name: 'Alice', city: 'London' });
113+
const headers = ['name', 'city'];
114+
```
115+
116+
Luego, necesitamos obtener el ancho de cada columna. Como tenemos 2 columnas posibles, utilizaremos `map` para recorrer cada columna y obtener el ancho de cada valor en cada columna. En este caso, deberíamos obtener `[7, 8]`.
117+
118+
Como tenemos 2 columnas, realizaremos dos iteraciones. En la primera iteración, obtenemos el ancho de la columna `name`.
119+
120+
Utilizaremos `Math.max()` para obtener el ancho máximo de cada valor, tanto del nombre de la columna como de los valores de los objetos.
121+
122+
Para el nombre de la columna, obtenemos el ancho del nombre de la columna `name`, que es `4`. Para los valores de los objetos, obtenemos el ancho de cada valor en la columna `name`.
123+
124+
- Para el primer objeto, obtenemos el ancho del valor `Alice`, que es `5`.
125+
- Para el segundo objeto, obtenemos el ancho del valor `Bob`, que es `3`.
126+
- Para el tercer objeto, obtenemos el ancho del valor `Charlie`, que es `7`.
127+
128+
Una vez que tenemos los anchos de los valores de los objetos, utilizamos `Math.max()` para obtener el ancho máximo de cada valor en la columna `name`, que es `7`. Este será el ancho de la columna `name`.
129+
130+
```js
131+
const columnWidths = headers.map((header) =>
132+
Math.max(header.length, ...data.map((row) => `${row[header]}`.length)),
133+
);
134+
135+
// Para esta primera iteración, el parametro header es 'name'
136+
137+
// Math.max('name'.length, ...data.map((row) => `${row['name']}`.length))
138+
// Math.max(4, 'Alice'.length, 'Bob'.length, 'Charlie'.length)
139+
// Math.max(4, 5, 3, 7)
140+
return 7
141+
```
142+
143+
En la segunda iteración, realizamos el mismo proceso que en la primera iteración para obtener el ancho de la columna `city`. En este caso, deberíamos obtener `8`.
144+
145+
```js
146+
// Para esta segunda iteración, el parametro header es 'city'
147+
148+
// Math.max('city'.length, ...data.map((row) => `${row['city']}`.length))
149+
// Math.max(4, 'London'.length, 'Paris'.length, 'New York'.length)
150+
// Math.max(4, 6, 5, 8)
151+
return 8
152+
```
153+
154+
Para este momento, `columnWidths` contiene los anchos de las columnas. En este caso, contiene `[7, 8]`.
155+
156+
```js
157+
// const columnWidths = headers.map((header) =>
158+
// Math.max(header.length, ...data.map((row) => `${row[header]}`.length)),
159+
// );
160+
161+
const columnWidths = [7, 8];
162+
```
163+
164+
Una vez que tenemos los anchos de las columnas, necesitamos crear el separador de la tabla, como lo ocuparemos 3 veces, lo guardaremos en una variable `separator`.
165+
166+
Utilizaremos `map` para recorrer cada columna y crear el separador de la tabla.
167+
168+
```js
169+
const separator = `+${columnWidths
170+
.map((width) => '-'.repeat(width + 2))
171+
.join('+')}+`;
172+
173+
// Para la primera iteración, el parametro width es 7
174+
175+
// '-'.repeat(width + 2)
176+
// '-'.repeat(7 + 2)
177+
// '-'.repeat(9)
178+
'---------'
179+
180+
// Para la segunda iteración, el parametro width es 8
181+
182+
// '-'.repeat(width + 2)
183+
// '-'.repeat(8 + 2)
184+
// '-'.repeat(10)
185+
'----------'
186+
187+
// En este momento, tendriamos que unir los dos valores obtenidos
188+
// '+ ['---------', '----------'].join('+') +'
189+
// '+ ---------+---------- +'
190+
return '+---------+----------+'
191+
```
192+
193+
En este momento, `separator` contiene el separador de la tabla.
194+
195+
```js
196+
// const separator = `+${columnWidths
197+
// .map((width) => '-'.repeat(width + 2))
198+
// .join('+')}+`;
199+
200+
const separator = '+---------+----------+';
201+
```
202+
203+
Una vez que tenemos los anchos de las columnas, necesitamos crear el encabezado de la tabla, con la primera letra en mayúscula, dejando un espacio a la izquierda y dejando a la derecha el espacio necesario para alinear la caja.
204+
205+
Utilizaremos `map` para recorrer cada columna y crear el encabezado de la tabla.
206+
207+
Internamente, utilizaremos `padEnd` para alinear el encabezado a la izquierda y dejar a la derecha el espacio necesario para alinear la caja.
208+
209+
```js
210+
const headerRowFormatted = `| ${headers
211+
.map((header, i) => {
212+
const headerFormatted = header.charAt(0).toUpperCase() + header.slice(1);
213+
return headerFormatted.padEnd(columnWidths[i]);
214+
})
215+
.join(' | ')} |`;
216+
217+
// Para la primera iteración, el parametro header es 'name' y el parametro i es 0
218+
219+
// header.charAt(0).toUpperCase() + header.slice(1)
220+
// 'name'.charAt(0).toUpperCase() + 'name'.slice(1)
221+
// 'N' + 'ame'
222+
'Name'
223+
224+
// 'Name'.padEnd(columnWidths[i])
225+
// 'Name'.padEnd(columnWidths[0])
226+
// 'Name'.padEnd(7)
227+
'Name '
228+
229+
// Para la segunda iteración, el parametro header es 'city' y el parametro i es 1
230+
231+
// header.charAt(0).toUpperCase() + header.slice(1)
232+
// 'city'.charAt(0).toUpperCase() + 'city'.slice(1)
233+
// 'C' + 'ity'
234+
'City'
235+
236+
// 'City'.padEnd(columnWidths[i])
237+
// 'City'.padEnd(columnWidths[1])
238+
// 'City'.padEnd(8)
239+
'City '
240+
241+
// En este momento, tendriamos que unir los dos valores obtenidos
242+
// '| ['Name ', 'City '].join(' | ') |'
243+
// '| Name | City |'
244+
return '| Name | City |'
245+
```
246+
247+
En este momento, `headerRowFormatted` contiene la fila de la cabecera de la tabla.
248+
249+
```js
250+
// const headerRowFormatted = `| ${headers
251+
// .map((header, i) => {
252+
// const headerFormatted = header.charAt(0).toUpperCase() + header.slice(1);
253+
// return headerFormatted.padEnd(columnWidths[i]);
254+
// })
255+
// .join(' | ')} |`;
256+
257+
const headerRowFormatted = '| Name | City |';
258+
```
259+
260+
Una vez que tenemos la fila de la cabecera, necesitamos crear las filas de los objetos. Es importante tener en cuenta que cada fila debe contener los valores de los objetos en el orden correspondiente, debe dejar un espacio a la izquierda y debe dejar a la derecha el espacio necesario para alinear la caja. Utilizaremos `map` para recorrer cada objeto y crear las filas de los objetos.
261+
262+
```js
263+
const rows = data.map(
264+
(row) =>
265+
`| ${headers
266+
.map((key, i) => `${row[key]}`.padEnd(columnWidths[i]))
267+
.join(' | ')} |`,
268+
);
269+
270+
// Para la primera iteración, el parametro row es { name: 'Alice', city: 'London' }
271+
// Como tenemos dos columnas, realizaremos dos iteraciones para la primera fila
272+
273+
// Para la primera iteración, el parametro key es 'name' y el parametro i es 0
274+
275+
// `${row[key]}`.padEnd(columnWidths[i])
276+
// `${row['name']}`.padEnd(columnWidths[0])
277+
// `'Alice'.padEnd(7)`
278+
'Alice '
279+
280+
// Para la segunda iteración, el parametro key es 'city' y el parametro i es 1
281+
282+
// `${row[key]}`.padEnd(columnWidths[i])
283+
// `${row['city']}`.padEnd(columnWidths[1])
284+
// `'London'.padEnd(8)`
285+
'London '
286+
287+
// En este momento, tendriamos que unir los dos valores obtenidos
288+
// '| ['Alice ', 'London '].join(' | ') |'
289+
// '| Alice | London |'
290+
return '| Alice | London |'
291+
292+
// Para la segunda iteración, el parametro row es { name: 'Bob', city: 'Paris' }
293+
// Como tenemos dos columnas, realizaremos dos iteraciones para la segunda fila
294+
295+
// Para la primera iteración, el parametro key es 'name' y el parametro i es 0
296+
297+
// `${row[key]}`.padEnd(columnWidths[i])
298+
// `${row['name']}`.padEnd(columnWidths[0])
299+
// `'Bob'.padEnd(7)`
300+
'Bob '
301+
302+
// Para la segunda iteración, el parametro key es 'city' y el parametro i es 1
303+
304+
// `${row[key]}`.padEnd(columnWidths[i])
305+
// `${row['city']}`.padEnd(columnWidths[1])
306+
// `'Paris'.padEnd(8)`
307+
'Paris '
308+
309+
// En este momento, tendriamos que unir los dos valores obtenidos
310+
// '| ['Bob ', 'Paris '].join(' | ') |'
311+
// '| Bob | Paris |'
312+
return '| Bob | Paris |'
313+
314+
// Para la tercera iteración, el parametro row es { name: 'Charlie', city: 'New York' }
315+
// Como tenemos dos columnas, realizaremos dos iteraciones para la tercera fila
316+
317+
// Para la primera iteración, el parametro key es 'name' y el parametro i es 0
318+
319+
// `${row[key]}`.padEnd(columnWidths[i])
320+
// `${row['name']}`.padEnd(columnWidths[0])
321+
// `'Charlie'.padEnd(7)`
322+
'Charlie '
323+
324+
// Para la segunda iteración, el parametro key es 'city' y el parametro i es 1
325+
326+
// `${row[key]}`.padEnd(columnWidths[i])
327+
// `${row['city']}`.padEnd(columnWidths[1])
328+
// `'New York'.padEnd(8)`
329+
'New York '
330+
331+
// En este momento, tendriamos que unir los dos valores obtenidos
332+
// '| ['Charlie ', 'New York '].join(' | ') |'
333+
// '| Charlie | New York |'
334+
return '| Charlie | New York |'
335+
```
336+
337+
Para este momento, `rows` contiene las filas de los objetos.
338+
339+
```js
340+
// const rows = data.map(
341+
// (row) =>
342+
// `| ${headers
343+
// .map((key, i) => `${row[key]}`.padEnd(columnWidths[i]))
344+
// .join(' | ')} |`,
345+
// );
346+
347+
const rows = [
348+
'| Alice | London |',
349+
'| Bob | Paris |',
350+
'| Charlie | New York |'
351+
]
352+
```
353+
354+
Finalmente, necesitamos unir todas las partes de la tabla. Utilizaremos `join` para unir todas las partes de la tabla
355+
356+
Nuestras variables contienen lo siguiente:
357+
358+
```js
359+
const separator = '+---------+----------+';
360+
const headerRowFormatted = '| Name | City |';
361+
const rows = [
362+
'| Alice | London |',
363+
'| Bob | Paris |',
364+
'| Charlie | New York |'
365+
];
366+
```
367+
368+
Generamos un array con todas las partes de la tabla y lo unimos con un salto de línea. Primero, unimos el separador, luego la fila de la cabecera, luego el separador, luego las filas de los objetos y finalmente el separador.
369+
370+
```js
371+
// return [separator, headerRow, separator, ...rows, separator].join('\n');
372+
return [
373+
'+---------+-----------+', // -> separador
374+
'| Name | City |', // -> fila de la cabecera
375+
'+---------+-----------+', // -> separador
376+
'| Alice | London |', //
377+
'| Bob | Paris |', // -> filas de los objetos
378+
'| Charlie | New York |', //
379+
'+---------+-----------+' // -> separador
380+
].join('\n')
381+
```
382+
383+
En este momento, la función `drawTable` devuelve la tabla de texto generada.
384+
385+
```js
386+
+---------+-----------+
387+
| Name | City |
388+
+---------+-----------+
389+
| Alice | London |
390+
| Bob | Paris |
391+
| Charlie | New York |
392+
+---------+-----------+
393+
```
394+
395+
Y eso es todo. Hemos completado el reto con éxito 🎉

0 commit comments

Comments
 (0)