First item from a Map on JavaScript ES2015 - javascript

I have a Map like this:
const m = new Map();
m.set('key1', {})
.
m.set('keyN' {})
the Mapcan have 1 or many items. Can I get the first item by index, without m.get('key1') and without a iterator loop?
like: m.get()[0]

Use the Map.prototype.entries function, like this
const m = new Map();
m.set('key1', {})
m.set('keyN', {})
console.log(m.entries().next().value); // [ 'key1', {} ]
If you want to get the first key, then use Map.prototype.keys, like this
console.log(m.keys().next().value); // key1
Similarly if you want to get the first value, then you can use Map.prototype.values, like this
console.log(m.values().next().value); // {}
The reason why we have to call next() on the returned values is that, all those functions return iterators. Read more about the iteration protocol here.

For the specific example you are wondering about, destructuring would be perfect.
let m = new Map();
m.set('key1', {});
m.set('key2', {});
let [[, obj]] = m;
e.g.
let [pair] = m;
let [key, obj] = pair;
is one option to destructure and then grab the value, but the easier option would be
let [obj] = m.values();

It could also be done using the spread feature at ES6 and the next versions. Let's declare a new Map variable, then add two values.
After that, we will use ... to convert the map into array or you can use Array.from then to get the first element just use [0] on the gotten array.
const m = new Map();
m.set('key1', 1);
m.set('key2', 2);
console.log([...m][0]); // ['key1', 1] 👍🏼
Or quickly by using distruct feature for javascript array, so that [k, v] array refers to first item at the map.
const [[k, v]] = m;
console.log(k, v); // 'key1', 1

Also, that is correct for both Set and Map: you can convert anything to Array and then get any element by its index. Something like this:
const m = new Map();
m.set('key1', {});
m.set('key2', {});
console.log(Array.from(m)[0]); // ['key1', {}]

For all iterable objects you can use the iterator object[Symbol.iterator]().
In our case this will point to the entries() method as explained in the above MDN page :
The map iterator function, which is the entries() function by default.
const m = new Map();
m.set('key1', {})
m.set('keyN', {})
console.log(m[Symbol.iterator]().next().value); // [ 'key1', {} ]
And here is a benchmark of all solutions :
https://jsbench.me/9fkpm6q9y0/1
The entries() version wins but it is very tight to the iterator version. This is logical since [Symbol.iterator]() calls entries().

Related

Javascript or Query - Convert Associative Array into Object

This is a simple question, not an expert in JS by any means and searched around but couldn't get any existing examples on Stackoverflow to work.
Basically I have a associative array and I need to convert it into an object:
Example:
var combinedproducts = [["Testing-1","test-1"],["Testing-2","test2"],["Testing-3","test3"]]
Need it to become this:
var products = {
// 'productid1':'Product Description One',
'Testing-1':'test-1',
'Testing-2':'test-2',
'Testing-3':'test-3'
};
What's the best / simplest way to do this? I can use regular javascript or jquery.
Thanks for the help!
If you don't have particular support issues, you can simply use Object.fromEntries, assuming "test2" and "test3" are actually array typos rather than intended to be transformed to test-2 and test-3 respectively as in your sample output.
Otherwise, you need to apply transformation to them (in that case, either reduce, a simple for or a foreach or even map can accomplish that).
Beware that, as mentioned above, Object.entries has not the same support as other solutions. For instance, keep in mind that it WON'T work in IE and Edge in general, check this link for further compatibility informations.
var combinedproducts = [["Testing-1","test-1"],["Testing-2","test2"],["Testing-3","test3"]];
const products = Object.fromEntries(combinedproducts);
console.log(products);
You can do it with .reduce() on your source array:
let object = combinedProducts.reduce((o, a) => (
o[a[0]] = a[1],
o
), {});
For what it's worth, the source array isn't really an "associative array" in any formal sense. JavaScript doesn't have an associative array type.
You can use array reduce. Inside the callback function add the first element of the inner array as key and the second element as the value
let data = [
["Testing-1", "test-1"],
["Testing-2", "test2"],
["Testing-3", "test3"]
];
let newData = data.reduce((acc, curr) => {
acc[curr[0]] = curr[1]
return acc;
}, {});
console.log(newData)
you can also use this method
const c = [["Testing-1","test-1"],["Testing-2","test2"],["Testing-3","test3"]];
obj = c.reduce((acc, [ key, val ]) => Object.assign(acc, { [key]: val }), {});
console.log(obj)
One more alternate way doing in one line with Object.assign and map.
var combinedproducts = [
["Testing-1", "test-1"],
["Testing-2", "test2"],
["Testing-3", "test3"]
];
const obj = Object.assign(
{},
...combinedproducts.map(([key, value]) => ({ [key]: value }))
);
console.log(obj);

Javascript: Convert a JSON string into ES6 map or other to preserve the order of keys

Is there a native (built in) in ES6 (or subsequent versions), Javascript or in TypeScript method to convert a JSON string to ES6 map OR a self-made parser to be implemented is the option? The goal is to preserve the order of the keys of the JSON string-encoded object.
Note: I deliberately don't use the word "parse" to avoid converting a JSON string first to ECMA script / JavaScript object which by definition has no order of its keys.
For example:
{"b": "bar", "a": "foo" } // <-- This is how the JSON string looks
I need:
{ b: "bar", a: "foo" } // <-- desired (map version of it)
UPDATE
https://jsbin.com/kiqeneluzi/1/edit?js,console
The only thing that I do differently is to get the keys with regex to maintain the order
let j = "{\"b\": \"bar\", \"a\": \"foo\", \"1\": \"value\"}"
let js = JSON.parse(j)
// Get the keys and maintain the order
let myRegex = /\"([^"]+)":/g;
let keys = []
while ((m = myRegex.exec(j)) !== null) {
keys.push(m[1])
}
// Transform each key to an object
let res = keys.reduce(function (acc, curr) {
acc.push({
[curr]: js[curr]
});
return acc
}, []);
console.log(res)
ORIGINAL
If I understand what you're trying to achieve for option 2. Here's what I came up with.
https://jsbin.com/pocisocoya/1/edit?js,console
let j = "{\"b\": \"bar\", \"a\": \"foo\"}"
let js = JSON.parse(j)
let res = Object.keys(js).reduce(function (acc, curr) {
acc.push({
[curr]: js[curr]
});
return acc
}, []);
console.log(res)
Basically get all the keys of the object, and then reduce it. What the reducer function convert each keys to an object
function jsonToMap(jsonStr) {
return new Map(JSON.parse(jsonStr));
}
More details : http://2ality.com/2015/08/es6-map-json.html
use for in loop
let map = new Map();
let jsonObj = {a:'a',b:'b',c:'c'}
for (let i in jsonObj){
map.set(i,jsonObj[i]);
}
btw, i saw the comment below and i think map is not ordered because you use key to achieve data in map, not the index.

Lodash how to assign specific property of object during comparing two collections of different objects

I have one question. Is there any function in lodash library which is going to provide me the method for comparing each object in both collections by specific property and if the condition is fulfilled then creating another object?
example:
a) [{a:1,b:'abc',c:'dfr'},{a:3,b:'dfe',c:'gty'}....{}]
b) [{a:3,b:'fgt',d:'ghr'},{a:5,b:'ghk',d:'bhj'}...{}]
result:[{a:3,b:'dfe',c:'gty',d:'ghr'}]
I would like to compare these two collections by 'a' parameter and if a parameter is matched then assign parameter 'd' to object from the collection a). I have read something about differenceWith or intersection, but I am not sure if it may work, or maybe there are better functions to do this. Thanks in advance!
Create a Map of the items in array2 by their keys. Iterate array1 with Array.filter(), and remove all items that their a property is not found in the Map. Use Array.map() to combine the remaining items with d property of their counterpart in the Map:
const array1 = [{a:1,b:'abc',c:'dfr'},{a:3,b:'dfe',c:'gty'}];
const array2 = [{a:3,b:'fgt',d:'ghr'},{a:5,b:'ghk',d:'bhj'}];
// create a Map of array2 items by the a property
const array2Map = new Map(array2.map((o) => [o.a, o]));
const result = array1
// filter out all items that don't have matching item in the Map
.filter(o => array2Map.has(o.a))
// map the items, and add the d property from the item in the Map
.map(o => ({
...o,
d: array2Map.get(o.a).d
}));
console.log(result);
1) Native way: doing array map and comparing inside map loop with assigning objects.
const array1 = [{a:1,b:'abc',c:'dfr'},{a:3,b:'dfe',c:'gty'}];
const array2 = [{a:3,b:'fgt',d:'ghr'},{a:5,b:'ghk',d:'bhj'}];
const result = array1.map(obj1 => {
const obj2 = array2.find(obj => obj.a === obj1.a);
if (obj2) return Object.assign({}, obj1, {d: obj2.d});
}).filter(value => value);
console.log(result);
2) Lodash way: same as in example 1 but using only lodash methods
const array1 = [{a:1,b:'abc',c:'dfr'},{a:3,b:'dfe',c:'gty'}];
const array2 = [{a:3,b:'fgt',d:'ghr'},{a:5,b:'ghk',d:'bhj'}];
const result = _.compact(
_.map(array1, obj1 => {
const obj2 = _.find(array2, _.matchesProperty('a', obj1.a));
if (obj2) return _.assign({}, obj1, _.pick(obj2, ['d']));
})
);
console.log(result);
<script src="https://cdn.jsdelivr.net/npm/lodash#4.17.10/lodash.min.js"></script>
P.S. Try to avoid lodash, underscore and etc stuff as much as possible. JS, ES are rich enough.

Loop in const object

I am trying to do the following:
const obj {
for(i=0;i<data.length;i++){
Key[i]: data[i].description
}
}
(I know I probably also needs to add a comma at the end of each line except on the last one, but I already get errors in the earlier stage)
This doesn't seem to be allowed in JS. Are there any alternatives? Thank you!
You could use Object.assign in combination with spread syntax ... and map the single objects with Array#map and use computed property names for the object.
const obj = Object.assign(...data.map((o, i) => ({ ['Key' + i]: o.description })));
It looks like you're trying to create an object from a keys array and a data array.
A clean approach would be to use array reduction:
const obj = data.reduce((obj, d, i) => {
obj[Key[i]] = d.description;
return obj;
}, {});
which, assuming your environment allows it, can be simplified further (due note that this will be cleaner code but less efficient because the object spread copies the entire object every time):
const obj = data.reduce((obj, d, i) => ({
...obj,
[Key[i]]: d.description
}), {});
but you could also use a simple for loop:
const obj = {};
for (let i = 0; i < data.length; i++) {
obj[Key[i]] = data[i].description;
}
Note: The code above will break if Key.length !== data.length.

How to convert a plain object into an ES6 Map?

For some reason I can't find this simple thing in the MDN docs (maybe I'm just missing it).
I expected this to work:
const map = new Map({foo: 'bar'});
map.get('foo'); // 'bar'
...but the first line throws TypeError: (var)[Symbol.iterator] is not a function
How do I make a Map from a plain object? Do I really have to first convert it into an array of arrays of key-value pairs?
Yes, the Map constructor takes an array of key-value pairs.
Object.entries is a new Object static method available in ES2017 (19.1.2.5).
const map = new Map(Object.entries({foo: 'bar'}));
map.get('foo'); // 'bar'
It's currently implemented in Firefox 46+ and Edge 14+ and newer versions of Chrome
If you need to support older environments and transpilation is not an option for you, use a polyfill, such as the one recommended by georg:
Object.entries = typeof Object.entries === 'function' ? Object.entries : obj => Object.keys(obj).map(k => [k, obj[k]]);
Do I really have to first convert it into an array of arrays of key-value pairs?
No, an iterator of key-value pair arrays is enough. You can use the following to avoid creating the intermediate array:
function* entries(obj) {
for (let key in obj)
yield [key, obj[key]];
}
const map = new Map(entries({foo: 'bar'}));
map.get('foo'); // 'bar'
The answer by Nils describes how to convert objects to maps, which I found very useful. However, the OP was also wondering where this information is in the MDN docs. While it may not have been there when the question was originally asked, it is now on the MDN page for Object.entries() under the heading Converting an Object to a Map which states:
Converting an Object to a Map
The new Map() constructor accepts an iterable of entries. With Object.entries, you can easily convert from Object to Map:
const obj = { foo: 'bar', baz: 42 };
const map = new Map(Object.entries(obj));
console.log(map); // Map { foo: "bar", baz: 42 }
ES6
convert object to map:
const objToMap = (o) => new Map(Object.entries(o));
convert map to object:
const mapToObj = (m) => [...m].reduce( (o,v)=>{ o[v[0]] = v[1]; return o; },{} )
Note: the mapToObj function assumes map keys are strings (will fail otherwise)
const myMap = new Map(
Object
.keys(myObj)
.map(
key => [key, myObj[key]]
)
)
Alternatively you can use the lodash toPairs method:
const _ = require('lodash');
const map = new Map(_.toPairs({foo: 'bar'}));

Categories

Resources