How to convert Map keys to array? - javascript

Lets say I have the following map:
let myMap = new Map().set('a', 1).set('b', 2);
And I want to obtain ['a', 'b'] based on the above. My current solution seems so long and horrible.
let myMap = new Map().set('a', 1).set('b', 2);
let keys = [];
for (let key of myMap)
keys.push(key);
console.log(keys);
There must be a better way, no?

Map.keys() returns a MapIterator object which can be converted to Array using Array.from:
let keys = Array.from( myMap.keys() );
// ["a", "b"]
EDIT: you can also convert iterable object to array using spread syntax
let keys =[ ...myMap.keys() ];
// ["a", "b"]

You can use the spread operator to convert Map.keys() iterator in an Array.
let myMap = new Map().set('a', 1).set('b', 2).set(983, true)
let keys = [...myMap.keys()]
console.log(keys)

OK, let's go a bit more comprehensive and start with what's Map for those who don't know this feature in JavaScript... MDN says:
The Map object holds key-value pairs and remembers the original
insertion order of the keys.
Any value (both objects and primitive
values) may be used as either a key or a value.
As you mentioned, you can easily create an instance of Map using new keyword...
In your case:
let myMap = new Map().set('a', 1).set('b', 2);
So let's see...
The way you mentioned is an OK way to do it, but yes, there are more concise ways to do that...
Map has many methods which you can use, like set() which you already used to assign the key values...
One of them is keys() which returns all the keys...
In your case, it will return:
MapIterator {"a", "b"}
and you easily convert them to an Array using ES6 ways, like spread operator...
const b = [...myMap.keys()];

I need something similiar with angular reactive form:
let myMap = new Map().set(0, {status: 'VALID'}).set(1, {status: 'INVALID'});
let mapToArray = Array.from(myMap.values());
let isValid = mapToArray.every(x => x.status === 'VALID');

Not exactly best answer to question but this trick new Array(...someMap) saved me couple of times when I need both key and value to generate needed array. For example when there is need to create react components from Map object based on both key and value values.
let map = new Map();
map.set("1", 1);
map.set("2", 2);
console.log(new Array(...map).map(pairs => pairs[0])); -> ["1", "2"]

Side note, if you are using a JavaScript object instead of a map, you can use Object.keys(object) which will return an array of the keys. Docs: link
Note that a JS object is different from a map and can't necessarily be used interchangeably!

Related

Using ECMA6 Set as object key

Is there a way to use Set as object keys
let x = {}
const a = new Set([3, 5])
x[a] = 1
console.log(x) // >{[object Set]: 1}
const b = new Set([1, 4])
x[b] = 2
console.log(x) // >{[object Set]: 2}
The keys are being overwritten even though the sets are not equal.
Thanks!
No this is not possible because Object keys must be strings or symbols. If you would like to use a Set as a key you can try using a Map. Maps are similar to objects except you can use other objects as keys for a map.
One thing to keep in mind is that you cannot use maps exactly like you use Objects.
This is directly from the Mozilla docs.
The following IS NOT A VALID USE OF A MAP.
let wrongMap = new Map()
wrongMap['bla'] = 'blaa'
wrongMap['bla2'] = 'blaaa2'
console.log(wrongMap) // Map { bla: 'blaa', bla2: 'blaaa2' }
But that way of setting a property does not interact with the Map data structure. It uses the feature of the generic object. The value of 'bla' is not stored in the Map for queries. Other operations on the data fail:
Correct use of a map looks like the below:
let map = new Map()
// setting values
map.set(key, value)
// getting values
map.get(key)
Remember that if you use an Object like a Set as a key, the reference of the Set is what matters.
If you instantiate two sets separately, even if they both have the same contents, they will have different references and be considered different keys.
Do you mean that the map in ES6 like this:
x = new Map()
a = new Set([3, 5])
x.set(a, 1)
console.log(x);

javascript merge to array with name

I am new in JS. It is a simple task but find it is hard to solve. I tried many methods includingconcat,push,$.merge
Here is an example
var a=[]
var b=[]
a["a"]="b"
a["c"]="d"
b["e"]="f"
b["g"]="h"
I want to get a result like [a:"b", c:"d", e:"f", g:"h"],
Here is some method I have tried
a.concat(b)get []
a.push(b) get 1
$.merge(a,b) get [0:[e:"f", g:"h"],a:"b",c:"d"]
I don't know where to go, Please help
The biggest problem you're running into right now is that you are trying to use an array as an object, so first when you're initializing a and b you should use curly braces instead. And then to merge them, you can use the spread operator: ....
All of that culminates into this:
let a = {};
let b = {};
a["a"]="b"
a["c"]="d"
b["e"]="f"
b["g"]="h"
a = {...a, ...b}
You cant get an array with key-value pairs its an invalid syntax, but you can create an object. Just spread both of your objects into an single object:
var a=[]
var b=[]
a["a"]="b"
a["c"]="d"
b["e"]="f"
b["g"]="h"
let result = {...a,...b};
console.log(result);

Output all values of a Set of strings

In JavaScript, what is the shortest code to output, for debugging purposes, all elements of a Set of strings? It doesn't matter if the strings are on one line or individual lines.
const set = new Set();
set.add('dog');
set.add('cat');
console.log(???);
You can use Spread syntax:
Spread syntax allows an iterable such as an array expression or string to be expanded in places where zero or more arguments (for function calls) or elements (for array literals) are expected, or an object expression to be expanded in places where zero or more key-value pairs (for object literals) are expected.
const set = new Set();
set.add('dog');
set.add('cat');
console.log(...set);
You can create an Array out of the Set, then log that:
const set = new Set();
set.add('dog');
set.add('cat');
console.log(Array.from(set));
You can use the ES6 method
.forEach()
So in full:
const set = new Set();
set.add('dog');
set.add('cat');
set.forEach(item => console.log(item))

How to initialize array length and values simultaneously in new Array()?

Let’s consider, I have to initialize an Array with some values
So I can achieve this by writing following code.
var arr = new Array("a", "b", "c", "d")
console.log(arr)
Similarly, I have to determine the length of the array before using it.
So I can achieve this by following code.
var arr = new Array(5)
console.log(arr.length)
Finally, I have a following questions ?
Is it possible to initialize an array with array length and different values (not similar values) simultaneously using new Array() ?
How to initialize a single integer value using new Array() ?
EDIT:
here, different values refers there are some specific string values.
I know it is straightforward when using array literals. but that's not exactly what I want.
The answer for both questions is no. Looking at the docs, there are two overloads for the Array function.
A JavaScript array is initialized with the given elements, except in the case where a single argument is passed to the Array constructor and that argument is a number (see the arrayLength parameter below).
If the only argument passed to the Array constructor is an integer between 0 and 232-1 (inclusive), this returns a new JavaScript array with its length property set to that number.
Only these two possibilities exist, there is no overload for specifying both the size and the values of an array.
You can create and fill an array like so:
let a = Array(100).fill(null)
console.log(a)
Or to increment your filled values:
let i=0,a = Array(100).fill(0).flatMap(x=>[x+i++])
console.log(a)
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/flatMap
You could use .fill().
console.log(new Array(5).fill(2));
// [2, 2, 2, 2, 2]
Is it possible to initialize an array with array length and values simultaneously using new Array() ?
As far as I know, this isn't possible yet.
How to initialize a single integer value using new Array() ?
That would be k => new Array(1).fill(k). But if I had to choose, I'd use k => [k]. Note it is recommended not to use new Array() in other scenarios than to initialize it's lenght. But even then, you should rather be sure you are giving it an integer because the behaviour of new Array(n) is a bit erratic, and won't throw you an error when you wish it did.
Actually, I wish it was not possible to initialize an array with value using new Array(). The worst being using new Array(...args), whose behaviour will change dramatically when args is [5]. You should stick to [] arrays if you want to initialize an array with values.
Array("") gives [""]
Similarly Array([]) gives [[]] and Array({}), [{}]
Array(5) gives an array with 5 empty slots
Array(2.5) produces an Uncaught RangeError: Invalid array length.
Also, Array() gives []
Note: This is Chromium's behaviour. I didn't check Firefox.
There are few ways to create an array:
1) Literals
const a = [1,2,3];
console.log(a);
But you say you don't want to use it.
2) Array constructor:
const a = new Array(10); //array of length 10
console.log(a);
const b = new Array(1,2,3);
console.log(b); // array with elements 1,2,3
But you say that you don't want to go for it
3) Array.from
const a = Array.from(new Array(10), (val, ind) => ind); // array of 10 values and map applied to these elements
console.log(a);
Over these 3 ways, you have the Array.fill method, which can be called with static values only:
const a = new Array(10);
console.log(a.fill(5)); // array of 10 number elements with value of 5
Considering your case, maybe your solution could be to go with Array.from, using the map function you can provide as second parameter.
You could think to create some function like the following:
function createMyArray(length, start, end) {
return Array.from(new Array(length), (val, ind) => ind >= start && ind <= end ? ind : undefined);
}
console.log(createMyArray(5, 2, 4));
console.log(createMyArray(5, 1, 3));
console.log(createMyArray(10, 2, 6));
The question you should ask to yourself is: Where and how is the data I want to use coming from? Otherwise this is really too much vague
Is it possible to initialize an array with array length and different values (not similar values) simultaneously using new Array() ?
No you cannot do that with the Array constructor only.
An alternative way is to do it like this:
var a = ['a', 'b', 'c', 'd'];
a.length = 10;
console.log(a);
How to initialize a single integer value using new Array() ?
You can't. This is what happens when you try to do so according to the specification:
Array(len)
[...]
Let intLen be ToUint32(len).
If intLen ≠ len, throw a RangeError exception.
Let setStatus be Set(array, "length", intLen, true).
Assert: setStatus is not an abrupt completion.
Return array.
Use the other ways to create an array instead (e.g. [1] or Array.of(1)).
Here's a different but related take on initializing an array without using an array literal.
let arr = [...Array(10)].map((emptyItem, index) => index);
// [0,1,2,3,4,5,6,7,8,9]
I can't find documentation that matches how this expression is constructed, so I can't fully explain it. But it is using the spread syntax to spread 10 empty items into an array.

How to append values to ES6 Map

I am trying to learn about ES6 Map data structures and am having difficulty understanding some of their behaviour. I would like to create a Map with an Array as a value and append (push) new values onto the current value of the Map. For example:
let m = new Map()
m.set(1, []) // []
m.set(1, m.get(1).push(2)) // [[1, 1]]
I am confused as to why I do not get [2] as the value of m.get(1) above. How can I append values to the array in my map?
That's because the method push returns the size of the array after the insertion.
You can change your code to the following to append to an array:
m.get(1).push(2);
And it'll update the value in the map, there's no need to try to re-set the value again as the value is passed back as reference.
The best way to define a Map according to your need is to explicitly tell the Map, what kind of data you want to deal with.
in your case you want values in an array, we could get using a "string id" for example
In this case you will have this :
let map = new Map<String, Array<any>>
Then you can create items like map["key"] = ["lol", 1, null]
There is two thing. First as #Adriani6 said the push method do not returns a pointer to the array but the size of the array.
Secondly, you do not need to do an other m.set, because your push will affect directly the array behind the reference returned by m.get
function displayMap(m) {
m.forEach(function(val, key) {
console.log(key + " => " + val);
});
}
let m = new Map();
m.set(1, []);
displayMap(m);
m.get(1).push(20);
displayMap(m);
It fails, because the return of push() is the size of the array after push.
You can push the content after doing a get().
m.get(1).push(2);
If you want to test set() then write a a self executable function like this:
let m = new Map()
m.set(1, []) // []
console.log(m.get(1))
m.set(1, (() => {m.get(1).push(2);return m.get(1);})());
console.log(m.get(1))
Here's a working example of what you are trying to do (open console)
Have a look here. As you can see the push method returns the new length of the array you just mutated, hence your result.

Categories

Resources