Skip to content

Map and Set #263

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 24 commits into from
Jul 5, 2020
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
cd5ac90
mapset
vplentinax Jun 18, 2020
981da7f
update solution
EzequielCaste Jul 4, 2020
e4ceae7
update task
EzequielCaste Jul 4, 2020
78e1bfa
update solution
EzequielCaste Jul 4, 2020
e61c2a6
corrección de líneas
EzequielCaste Jul 4, 2020
1c79cbe
corrección número líneas
EzequielCaste Jul 4, 2020
883cd95
fixed line numbers
EzequielCaste Jul 4, 2020
e6f57ea
Update 1-js/05-data-types/07-map-set/01-array-unique-map/task.md
vplentinax Jul 4, 2020
af49a81
Update 1-js/05-data-types/07-map-set/01-array-unique-map/task.md
vplentinax Jul 4, 2020
459c874
Update 1-js/05-data-types/07-map-set/01-array-unique-map/task.md
vplentinax Jul 4, 2020
f6f6016
Update 1-js/05-data-types/07-map-set/01-array-unique-map/task.md
vplentinax Jul 4, 2020
438b4d7
Update 1-js/05-data-types/07-map-set/01-array-unique-map/task.md
vplentinax Jul 4, 2020
e101acc
Update 1-js/05-data-types/07-map-set/01-array-unique-map/task.md
vplentinax Jul 4, 2020
f754d71
Update 1-js/05-data-types/07-map-set/01-array-unique-map/task.md
vplentinax Jul 4, 2020
740687f
Update 1-js/05-data-types/07-map-set/03-iterable-keys/task.md
vplentinax Jul 4, 2020
444e0a5
Update 1-js/05-data-types/07-map-set/article.md
vplentinax Jul 4, 2020
669b0ff
Update 1-js/05-data-types/07-map-set/article.md
vplentinax Jul 4, 2020
c3f6fc4
Update 1-js/05-data-types/07-map-set/article.md
vplentinax Jul 4, 2020
b2df4f7
Update 1-js/05-data-types/07-map-set/article.md
vplentinax Jul 4, 2020
2c56508
Update 1-js/05-data-types/07-map-set/article.md
vplentinax Jul 4, 2020
74fee8b
Update 1-js/05-data-types/07-map-set/article.md
vplentinax Jul 4, 2020
3178435
Update 1-js/05-data-types/07-map-set/article.md
vplentinax Jul 4, 2020
3b5c116
Update 1-js/05-data-types/07-map-set/article.md
vplentinax Jul 4, 2020
7dcaca0
Update task.md
vplentinax Jul 4, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions 1-js/05-data-types/07-map-set/01-array-unique-map/task.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ importance: 5

---


# Filtrar miembros únicos del array

Permita que `arr` sea un array.
Expand All @@ -21,6 +22,8 @@ let values = ["Hare", "Krishna", "Hare", "Krishna",

alert( unique(values) ); // Hare, Krishna, :-O
```


P.D. Aquí se usan strings, pero pueden ser valores de cualquier tipo.

P.D.S. Use `Set` para almacenar valores únicos.
Expand Down
14 changes: 7 additions & 7 deletions 1-js/05-data-types/07-map-set/02-filter-anagrams/solution.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@

Para encontrar todos los anagramas, dividamos cada palabra en letras y las ordenamos. Cuando se clasifican las letras, todos los anagramas son iguales.

Por ejemplo:
Expand All @@ -10,7 +9,7 @@ cheaters, hectares, teachers -> aceehrst
...
```

Utilizaremos las variantes ordenadas por letras como propiedades de Map para almacenar solo un valor por cada propiedad:
Utilizaremos las variantes ordenadas por letras como claves de Map para almacenar solo un valor por cada clave:

```js run
function aclean(arr) {
Expand All @@ -23,13 +22,15 @@ function aclean(arr) {
*/!*
map.set(sorted, word);
}

return Array.from(map.values());
}

let arr = ["nap", "teachers", "cheaters", "PAN", "ear", "era", "hectares"];

alert( aclean(arr) );
```

La clasificación de letras se realiza mediante la cadena de llamadas en la línea `(*)`.

Por conveniencia la dividimos en múltiples líneas:
Expand All @@ -41,24 +42,23 @@ let sorted = arr[i] // PAN
.sort() // ['a','n','p']
.join(''); // anp
```

Dos palabras diferentes`'PAN'` y `'nap'` reciben la misma forma ordenada por letras `'anp'`.

La siguiente línea pone la palabra en el Map:


```js
map.set(sorted, word);
```

Si alguna vez volvemos a encontrar una palabra con la misma forma ordenada por letras, sobrescribiría el valor anterior con la misma propiedad en Map. Por lo tanto, siempre tendremos como máximo una palabra ordenada por letras.
Si alguna vez volvemos a encontrar una palabra con la misma forma ordenada por letras, sobrescribiría el valor anterior con la misma clave en Map. Por lo tanto, siempre tendremos como máximo una palabra ordenada por letras.

Al final, `Array.from (map.values())` toma un valor iterativo sobre los valores de Map (no necesitamos propiedades en el resultado) y devuelve un array de ellos.
Al final, `Array.from (map.values())` toma un valor iterativo sobre los valores de Map (no necesitamos claves en el resultado) y devuelve un array de ellos.

Aquí también podríamos usar un objeto plano en lugar del `Map`, porque las propiedades son strings.
Aquí también podríamos usar un objeto plano en lugar del `Map`, porque las claves son strings.

Así es como puede verse la solución:


```js run demo
function aclean(arr) {
let obj = {};
Expand Down
2 changes: 1 addition & 1 deletion 1-js/05-data-types/07-map-set/02-filter-anagrams/task.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,11 @@ Escriba una función `aclean(arr)` que devuelva un array limpio de anagramas.

Por ejemplo:


```js
let arr = ["nap", "teachers", "cheaters", "PAN", "ear", "era", "hectares"];

alert( aclean(arr) ); // "nap,teachers,ear" o "PAN,cheaters,era"
```

Es decir, de cada grupo de anagramas debe quedar solo una palabra, sin importar cual.

1 change: 1 addition & 0 deletions 1-js/05-data-types/07-map-set/03-iterable-keys/solution.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ Eso es porque `map.keys()` devuelve un iterable, pero no un array.

Podemos convertirlo en un array usando `Array.from`:


```js run
let map = new Map();

Expand Down
3 changes: 1 addition & 2 deletions 1-js/05-data-types/07-map-set/03-iterable-keys/task.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ importance: 5

---

# Propiedades iterables
# Claves iterables

Nos gustaría obtener un array de `map.keys()` en una variable y luego aplicarle métodos específicos de array, ej. .push.

Expand All @@ -22,4 +22,3 @@ keys.push("more");
```

¿Por qué? ¿Cómo podemos arreglar el código para que funcione `keys.push`?

101 changes: 55 additions & 46 deletions 1-js/05-data-types/07-map-set/article.md
Original file line number Diff line number Diff line change
@@ -1,66 +1,69 @@

# Map y Set

Hasta este momento, hemos aprendido sobre las siguientes estructuras de datos:

- Objetos para almacenar colecciones de propiedades.
- Objetos para almacenar colecciones de claves.
- Arrays para almacenar colecciones ordenadas.

Pero eso no es suficiente para la vida real. Por eso también existen Map y Set.

## Map

[Map](https://developer.mozilla.org/es/docs/Web/JavaScript/Referencia/Objetos_globales/Map) es una colección de elementos de datos con propiedad, al igual que un objeto, y valor. Pero la principal diferencia es que Map permite propiedades de cualquier tipo.
[Map](https://developer.mozilla.org/es/docs/Web/JavaScript/Referencia/Objetos_globales/Map) es una colección de elementos de datos con clave, al igual que un objeto, y valor. Pero la principal diferencia es que Map permite claves de cualquier tipo.

Los métodos y propiedades son:

- `new Map()` -- crea el mapa.
- `map.set(propiedad, valor)` -- almacena el valor para la propiedad.
- `map.get(propiedad)` -- devuelve el valor de la propiedad: será `undefined` si la `propiedad` no exite en Map.
- `map.has(propiedad)` -- devuelve`true` si la `propiedad` exite, y `false` si no existe.
- `map.delete(propiedad)` -- elimina los valores de la propiedad.
- `map.set(clave, valor)` -- almacena el valor para la clave.
- `map.get(clave)` -- devuelve el valor de la clave: será `undefined` si la `clave` no exite en Map.
- `map.has(clave)` -- devuelve`true` si la `clave` exite, y `false` si no existe.
- `map.delete(clave)` -- elimina los valores de la clave.
- `map.clear()` -- limpia el Map.
- `map.size` -- retorna el número del elemento actual en el recuento de elementos en el Map.

Por ejemplo:

```js run
let map = new Map();
map.set('1', 'str1'); // un string como propiedad
map.set(1, 'num1'); // un número como propiedad
map.set(true, 'bool1'); // un booleano como propiedad
// recuerda el objeto regular? convertiría las propiedades en un string
// Map mantiene el tipo de dato en las propiedades, por lo que estas dos son diferentes:

map.set('1', 'str1'); // un string como clave
map.set(1, 'num1'); // un número como clave
map.set(true, 'bool1'); // un booleano como clave

// recuerda el objeto regular? convertiría las claves en un string
// Map mantiene el tipo de dato en las claves, por lo que estas dos son diferentes:
alert( map.get(1) ); // 'num1'
alert( map.get('1') ); // 'str1'

alert( map.size ); // 3
```

Como podemos ver, a diferencia de los objetos, las propiedades no se convierten en strings. Cualquier tipo de propiedad es posible en un Map.
Como podemos ver, a diferencia de los objetos, las claves no se convierten en strings. Cualquier tipo de clave es posible en un Map.

```smart header="map[propiedad] no es la forma correcta para usar Map"
Aunque el map[propiedad] también funciona, por ejemplo, podemos establecer map[propiedad] = 2, esto es tratar a map como un objeto JavaScript simple, por lo que implica todas las limitaciones correspondientes (sin objetos como propiedad, etc.).
```smart header="map[clave] no es la forma correcta para usar Map"
Aunque el `map[clave]` también funciona, por ejemplo, podemos establecer `map[clave]` = 2, esto es tratar a `map` como un objeto JavaScript simple, por lo que implica todas las limitaciones correspondientes (sin objetos como clave, etc.).

Por lo tanto, deberíamos usar los métodos de `Map`: set, get, etc.
Por lo tanto, deberíamos usar los métodos de `Map`: `set`, `get`, etc.
```

**El mapa también puede usar objetos como propiedades.**
**El mapa también puede usar objetos como claves.**

Por ejemplo:

```js run
//John es un objeto
let john = { name: "John" };

// para cada usuario, almacenemos el recuento de visitas
let visitsCountMap = new Map();

// John es la propiedad para el Map
// john es la clave para el Map
visitsCountMap.set(john, 123);

alert( visitsCountMap.get(john) ); // 123
```
El uso de objetos como propiedades es una de las características de `Map` más notables e importantes. Para las propiedades de tipo string, `Object` puede estar bien, pero no para las propiedades de tipo objeto.

El uso de objetos como claves es una de las características de `Map` más notables e importantes. Para las claves de tipo string, `Object` puede estar bien, pero no para las claves de tipo objeto.

Intentémoslo:

Expand All @@ -69,16 +72,18 @@ let john = { name: "John" };

let visitsCountObj = {}; // intenta usar un objeto

visitsCountObj[john] = 123; // intenta usar el objeto john como propiedad
visitsCountObj[john] = 123; // intenta usar el objeto john como clave

*!*
// Esto es lo que se escribió!
alert( visitsCountObj["[object Object]"] ); // 123
*/!*
```

Como `visitsCountObj` es un objeto, convierte todas las propiedades, como John en string, por lo que tenemos la propiedad de tipo string `"[objeto Objeto]"`. Definitivamente no es lo que queremos.
Como `visitsCountObj` es un objeto, convierte todas las claves, como `john` en string, por lo que tenemos la clave de tipo string `"[objeto Objeto]"`. Definitivamente no es lo que queremos.

```smart header="Cómo `Map` compara las propiedades"
`Map` utiliza el algoritmo [SameValueZero](https://tc39.es/ecma262/#sec-samevaluezero). Es aproximadamente lo mismo que la igualdad estricta `===`, pero la diferencia es que `NaN` se considera igual a `NaN`. Por lo tanto, `NaN` también se puede usar como propiedad.
```smart header="Cómo `Map` compara las claves"
`Map` utiliza el algoritmo [SameValueZero](https://tc39.es/ecma262/#sec-samevaluezero). Es aproximadamente lo mismo que la igualdad estricta `===`, pero la diferencia es que `NaN` se considera igual a `NaN`. Por lo tanto, `NaN` también se puede usar como clave.

Este algoritmo no se puede cambiar ni personalizar.
```
Expand All @@ -93,12 +98,14 @@ map.set('1', 'str1')
```
````


## Iteración sobre Map

Para recorrer un `Map`, hay 3 métodos:

- `map.keys()` – devuelve un iterable para las propiedades.
- `map.keys()` – devuelve un iterable para las claves.
- `map.values()` – devuelve un iterable para los valores.
- `map.entries()` – devuelve un iterable para las entradas `[propiedad, valor]`, se usa por defecto en `for..of`.
- `map.entries()` – devuelve un iterable para las entradas `[clave, valor]`, se usa por defecto en `for..of`.

Por ejemplo:

Expand All @@ -109,7 +116,7 @@ let recipeMap = new Map([
['cebollas', 50]
]);

// iterando sobre las propiedades (verduras)
// iterando sobre las claves (verduras)
for (let vegetable of recipeMap.keys()) {
alert(vegetable); // pepino, tomates, cebollas
}
Expand All @@ -120,7 +127,7 @@ for (let amount of recipeMap.values()) {
alert(amount); // 500, 350, 50
}

// iterando sobre las entradas [propiedad, valor]
// iterando sobre las entradas [clave, valor]
for (let entry of recipeMap) { // lo mismo que recipeMap.entries()
alert(entry); // pepino,500 (etc)
}
Expand All @@ -132,18 +139,19 @@ La iteración va en el mismo orden en que se insertaron los valores. `Map` conse
Además de eso, `Map` tiene un método `forEach` incorporado, similar a `Array`:

```js
// recorre la función para cada par (propiedad, valor)
// recorre la función para cada par (clave, valor)
recipeMap.forEach( (value, key, map) => {
alert(`${key}: ${value}`); // pepino: 500 etc
});
```

## Object.entries: Map desde Objeto

Cuando se crea un `Map`, podemos pasar un array (u otro iterable) con pares propiedad / valor para la inicialización, de esta manera:
Cuando se crea un `Map`, podemos pasar un array (u otro iterable) con pares clave / valor para la inicialización, de esta manera:

```js run
// array de [propiedad, valor]
// array de [clave, valor]

let map = new Map([
['1', 'str1'],
[1, 'num1'],
Expand All @@ -152,7 +160,8 @@ let map = new Map([

alert( map.get('1') ); // str1
```
Aquí hay un método incorporado [Object.entries(obj)](https://developer.mozilla.org/es/docs/Web/JavaScript/Referencia/Objetos_globales/Object/entries) que devuelve un array de pares propiedad / valor para un objeto exactamente en ese formato.

Aquí hay un método incorporado [Object.entries(obj)](https://developer.mozilla.org/es/docs/Web/JavaScript/Referencia/Objetos_globales/Object/entries) que devuelve un array de pares clave / valor para un objeto exactamente en ese formato.

Entonces podemos inicializar un mapa desde un objeto como este:

Expand All @@ -167,12 +176,12 @@ let map = new Map(Object.entries(obj));
alert( map.get('name') ); // John
```

Aquí, `Object.entries` devuelve el array de pares propiedad / valor: [["" name "," John "], [" age ", 30]]. Eso es lo que necesita `Map`.
Aquí, `Object.entries` devuelve el array de pares clave / valor: [["" name "," John "], [" age ", 30]]. Eso es lo que necesita `Map`.

## Object.fromEntries: Objeto desde Map
Acabamos de ver cómo crear un `Map` a partir de un objeto simple con `Object.entries (obj).`

Existe el método `Object.fromEntries` que hace lo contrario: dado un array de pares [propiedad, valor], crea un objeto a partir de ellos:
Existe el método `Object.fromEntries` que hace lo contrario: dado un array de pares [clave, valor], crea un objeto a partir de ellos:

```js run
let prices = Object.fromEntries([
Expand Down Expand Up @@ -205,17 +214,17 @@ let obj = Object.fromEntries(map.entries()); // hace un objeto simple
alert(obj.orange); // 2
```

Una llamada a `map.entries()` devuelve un array de pares propiedad / valor, exactamente en el formato correcto para `Object.fromEntries.`
Una llamada a `map.entries()` devuelve un array de pares clave / valor, exactamente en el formato correcto para `Object.fromEntries.`

También podríamos acortar la línea 6 del ejemplo anterior:

```js
let obj = Object.fromEntries(map); // omitimos .entries()
```
Es lo mismo, porque `Object.fromEntries` espera un objeto iterable como argumento. No necesariamente un array. Y la iteración estándar para el `Map` devuelve los mismos pares propiedad / valor que `map.entries()`. Entonces obtenemos un objeto simple con las mismas propiedades / valores que `Map`.
Es lo mismo, porque `Object.fromEntries` espera un objeto iterable como argumento. No necesariamente un array. Y la iteración estándar para el `Map` devuelve los mismos pares clave / valor que `map.entries()`. Entonces obtenemos un objeto simple con las mismas claves / valores que `Map`.

## Set
`Set` es una colección de tipo especial: "conjunto de valores" (sin propiedades), donde cada valor puede aparecer solo una vez.
`Set` es una colección de tipo especial: "conjunto de valores" (sin claves), donde cada valor puede aparecer solo una vez.

Sus principales métodos son:

Expand Down Expand Up @@ -259,6 +268,7 @@ La alternativa a `Set` podría ser un array de usuarios y el código para verifi
## Iteración sobre Set
Podemos recorrer `Set` con `for..of` o usando `forEach`:


```js run
let set = new Set(["oranges", "apples", "bananas"]);

Expand All @@ -277,25 +287,25 @@ Eso es por compatibilidad con `Map` donde la función callback tiene tres argume

También soporta los mismos métodos que `Map` tiene para los iteradores:

- `set.keys()` – devuelve un iterable para las propiedades.
- `set.keys()` – devuelve un iterable para las claves.
- `set.values()` – lo mismo que `set.keys()`, por su compatibilidad con `Map`.
- `set.entries()` – devuelve un iterable para las entradas `[propiedad, valor]`, por su compatibilidad con `Map`.
- `set.entries()` – devuelve un iterable para las entradas `[clave, valor]`, por su compatibilidad con `Map`.

## Resumen
`Map`: es una colección de valores con propiedad.
`Map`: es una colección de valores con clave.

Métodos y propiedades:
- `new Map()` -- crea el mapa.
- `map.set(propiedad, valor)` -- almacena el valor para la propiedad.
- `map.get(propiedad)` -- devuelve el valor de la propiedad: será `undefined` si la `propiedad` no exite en Map.
- `map.has(propiedad)` -- devuelve`true` si la `propiedad` exite, y `false` si no existe.
- `map.delete(propiedad)` -- elimina los valores de la propiedad.
- `map.set(clave, valor)` -- almacena el valor para la clave.
- `map.get(clave)` -- devuelve el valor de la clave: será `undefined` si la `clave` no exite en Map.
- `map.has(clave)` -- devuelve`true` si la `clave` exite, y `false` si no existe.
- `map.delete(clave)` -- elimina los valores de la clave.
- `map.clear()` -- limpia el Map.
- `map.size` -- retorna el número del elemento actual en el recuento de elementos en el Map.

La diferencia con `Objeto` regular:
- Cualquier propiedad, los objetos tambien pueden ser propiedads.
- Adicionalmente tiene métodos que nos convienen, como la propiedad `size`.
- Cualquier clave, los objetos tambien pueden ser claves.
- Adicionalmente tiene métodos que nos convienen, como la clave `size`.

`Set`: es una colección de valores únicos.

Expand All @@ -308,4 +318,3 @@ Métodos y propiedades:
- `set.size` -- es el contador de los elementos.

La iteración sobre `Map` y `Set` siempre está en el orden de inserción, por lo que no podemos decir que estas colecciones están desordenadas, pero no podemos reordenar elementos u obtener un elemento directamente por su número.