I am using ES6 Set instances and I need to apply some transformations on them. These are transformations of the kind that would be simple if they were arrays. Here is an example:
let s = new Set;
s.add(1);
s.add(2);
s.add(3);
let n = s.filter(val => val > 1); // TypeError, filter not defined
let n = Array.prototype.filter.call(s, val => val > 1); // []
I was hoping that the result would either be a new Set or an array. I similarly want to use other array comprehension methods like filter, map, reduce, etc. And I would also like to have similar behaviour on ES6 Map instances as well.
Is this possible, or do I need to be using vanilla JS arrays?
you can get the values of s in an array using
Array.from(s.values())
Array.from documentation states that it creates a new Array instance from an array-like or iterable object.
Set.values returns a new Iterator object that contains the values for each element in the Set object in insertion order.
So your code becomes
let s = new Set;
s.add(1);
s.add(2);
s.add(3);
let n = Array.from(s.values()).filter(val => val > 1)
You can't use Array methods directly on a Set or Map object. Array methods expect .length and [n] indexing which is not how Set or Map work.
You can either convert your Set to an array using Array.from(s) or you can create your own methods to operate directly on the Set or Map. If you're going to be doing this a lot and the desired end result is a Set or Map, then it's probably better to not convert to an Array, modify, then convert back. Plus, converting a Map to an array is not quite so simple since you have both a key and value (might have to be an array of objects).
For example, you could create your own .filter() method for a Set object like this:
Set.prototype.filter = function(fn) {
let result = new Set();
for (let val of this) {
if (fn(val, this) === true) {
result.add(val);
}
}
return result;
}
let s = new Set;
s.add(1);
s.add(2);
s.add(3);
let n = s.filter(val => val > 1);
// log the output
// log output
document.write("Set {" + Array.from(n).join(", ") +"}");
Similar methods could be created for other Array methods.
Related
I have a map that consists of several key : value pairs, and the keys are all integers (that are then of course stored as strings).
However, I can't use Map.prototype.has("1") nor Map.prototype.has(1) to confirm a key exists within the map. How do I go about doing this? I want to use the Map.prototype.has() method in order to avoid the whole 0 is false problem.
let map = new Map();
map[1] = 2;
console.log(map); //Map { 1: 2 }
console.log(map.has("1")); //false
console.log(map.has(1)); //false
Use Map.prototype.set not map[1] = 2. Maps are Objects with their own set of rules, so you cannot set it the way above. Learn more here.
let map = new Map();
map.set(1,2);
console.log(map); // Map(1) { 1 => 2 }
console.log(map.has("1")); //false
console.log(map.has(1)); //true
When you do map[1] = 2; you're not setting the item in the map data structure itself, but on the underlying generic object. Therefore, you can't expect map related methods as has() and get() to return you "correct" results as the map structure is actually empty. Always set map properties with map.set().
Also, note that Map doesn't support indexing. You can't get an item by doing map[key]. This, once again, will access a property from the underlying object. You have to use map.get() instead.
You can see the difference by doing this:
let testMap = new Map();
testMap['prop1'] = 'prop1value';
testMap.set('prop2', 'prop2value');
testMap.set('prop1', 'prop1value');
console.log(testMap);
[[Entries]] is the actual map structure, everything else is coming from the object.
For completeness, object properties can only be strings or symbols. Map, on the other hand, support all types(including objects and functions). I am saying this because if you do:
let testMap = new Map();
testMap['1'] = 'prop1value';
testMap[1] = 'prop2value';
you actually mutate the same property('1', numeric keys are actually converted to strings). If you use the actual map structure, however:
let testMap = new Map();
testMap.set('1', 'prop1value');
testMap.set(1, 'prop2value');
You have two separate entries: '1' and 1.
I would like to use spread syntax to copy properties from several unknown objects into one object. Something like this:
var array = [{a:0}, {b:1}, {c:2}]; // This array could hold any number of objects
// This function should take the objects in the array and use spread syntax to create a new object.
function merge(arr) { /* Code I wish I knew */ } // returns an object
var combo = merge(array);
console.log(combo); // {a:0, b:1, c:2}
I am aware of Object.assign. My reason for asking this question is just to see if this sort of thing can be done with spread syntax. Additionally, I'm concerned with V8's Hidden Classes. From what I understand, modifying an object after it is instantiated negatively impacts the performance of the Hidden Class. I've read that Spread doesn't have this issue, possibly because it instantiates the object with all of the properties of the other objects.
You can use a combination of Array.reduce with Object.assign:
var array = [{a:0}, {b:1}, {c:2}];
function merge(arr) {
return array.reduce((x,y) => Object.assign(x, y))
//
// per the comments, if we don't want to mutate the original object we can do instead:
// return array.reduce((x,y) => Object.assign(x, y), {})
}
var combo = merge(array);
console.log(combo);
You can use Array#reduce to iterate the array and merge the children into one object:
var array = [{a:0}, {b:1}, {c:2}];
function merge(arr) {
return arr.reduce((acc, cur) => ({ ...acc, ...cur }));
}
var combo = merge(array);
console.log(combo);
I am fairly new to JS, I am struggling with a problem where there is an array of objects and i want to return true if any key value pair in the object is duplicate
var lookupValues = [{"key":"xiomi","value":"phone","id":1},{"key":"samsung","value":"tab",id:2},{"key":"blackberry","value":"phone","id":3},{"key":"xiomi","value":"tab","id":4},{"key":"asus","value":"phone",id:5}]}
Since key: "Xiomi" came twice so function should return true
i tried using lodash functions
var uniqueLookup =_uniqBy(lookupValues,'key')
if(_.isEqual(uniqueLookup, lookup)) return true
works but i guess i am missing something
You are on the right track. Compare the length of the array to the array shortened by checking if the key is unique.
var lookupValues = [{"key":"xiomi","value":"phone","id":1},{"key":"samsung","value":"tab",id:2},{"key":"blackberry","value":"phone","id":3},{"key":"xiomi","value":"tab","id":4},{"key":"asus","value":"phone",id:5}];
console.log(_.uniqBy(lookupValues,"key").length !== lookupValues.length);
<script src="https://cdn.jsdelivr.net/npm/lodash#4.17.19/lodash.min.js"></script>
Here how you can do this in VanillaJs.
Set is a new data structure that JavaScript got in ES6. It’s a collection of unique values. We put into that the list of property values we get from using map(), which how we used it will return this array:
[xiomi,Samsung,blackberry,xiomi,asus]
Passing through Set, we’ll remove the duplicates i.e xiomi and at last ... is the spread operator, which will expand the Set values into an array.
Now if length of this new array is equal to your lookupValues.length then it has no duplicates else duplicates are present.
var lookupValues = [{"key":"xiomi","value":"phone","id":1},{"key":"samsung","value":"tab",id:2},{"key":"blackberry","value":"phone","id":3},{"key":"xiomi","value":"tab","id":4},{"key":"asus","value":"phone",id:5}]
const isDuplicate = (lookupValues) => !([...new Set(lookupValues.map(obj => obj.key))].length === lookupValues.length)
console.log(isDuplicate(lookupValues))
I made a vanilla Javascript code snippet with es6 Set object.
var lookupValues = [{"key":"xiomi","value":"phone","id":1},{"key":"samsung","value":"tab",id:2},{"key":"blackberry","value":"phone","id":3},{"key":"xiomi","value":"tab","id":4},{"key":"asus","value":"phone",id:5}]
const keys = lookupValues.map((v) => v.key)
const keySetSize = new Set(keys).size
const hasDuplicate = keys.length > keySetSize
console.log(hasDuplicate)
I want to go through an array of strings, and depending on what the string is, make an array of objects.
For example, if the array is:
[a,a,a,b,b,c,d]
I want to map through the array and make an object with key and value pairs that add up the strings consecutively:
[{a:1},{a:2},{a:3},{b:1},{b:2},{c:1},{d:1}]
How do I do this?
I've tried mapping through, but I can't get how to add on to the previous object's value (a:1 -> a:2)
While mapping, you need to store a separate count of how many times each item has appeared, and increment the appropriate key each iteration. You might use a Map for this:
const input = ['a','a','a','b','b','c','d'];
const map = new Map();
console.log(
input.map(char => {
const count = (map.get(char) || 0) + 1;
map.set(char, count);
return { [char]: count };
})
)
I have a code :
var index = 100;
var arr =[];
arr[index.toString()] = "Hello"
The result : index still known as integer not a string. Anyone can explain what's wrong with my code?
You have to declare associative arrays using {}, which creates a new object, because in JavaScript, arrays always use numbered indexes.
You need to declare an object: var arr={};
arrays use numbered indexes.
objects use named indexes.
var index = 100;
var arr ={};
arr[index.toString()] = "Hello";
console.log(arr);
How to make associative array with number as string in Javascript
JavaScript doesn't have associative arrays in the sense that term is frequently used. It has objects, and as of ES2015 (aka "ES6"), it has Maps.
The result : index still known as integer not a string. Anyone can explain what's wrong with my code?
The index variable's value is still a number, yes, because you haven't done anything to change it. But the index in the array is a string (and would be even if you didn't use .toString()), because standard arrays aren't really arrays at all1, they're objects with special handling of a class of properties (ones whose names are strings that fit the spec's definition of an array index), a special length property, and that use Array.prototype as their prototype.
Here's proof that array indexes are strings:
var a = [];
a[0] = "zero";
for (var name in a) {
console.log("name == " + name + ", typeof name == " + typeof name);
}
That said, you don't want to use an array when you want a generic object or map.
Here's using a generic object for name/value mappings:
var o = Object.create(null);
var name = "answer";
o[name] = 42;
console.log(o[name]); // 42
The property names in objects are strings or (as of ES2015) Symbols. I used Object.create(null) to create the object so it wouldn't have Object.prototype as its prototype, since that gives us properties (toString, valueOf, etc.) that we don't want if we're using the object as a map.
Here's using a Map:
var m = new Map();
var name = "answer";
m.set(name, 42);
console.log(m.get(name)); // 42
The main advantages Maps have over objects are:
Their keys can be anything, not just strings or Symbols
They're iterable, so you can use for-of to loop through the mappings they contain
Maps have a size property telling you how many entries they have
Maps guarantee that iteration of their entries is performed in the order the entries were added to the map
With ES6, you could use a Map, which holds any type as key.
var map = new Map;
map.set(100, "Hello");
map.set('100', "Foo");
console.log(map.get(100)); // 'Hello'
console.log(map.get('100')); // 'Foo'
console.log([...map]);
JavaScript does not support arrays with named indexes, in JavaScript, arrays always use numbered indexes.
If you use a named index, JavaScript will redefine the array to a standard object.
After that, all array methods and properties will produce incorrect results.
As you can see in the following example:
var person = [];
person["firstName"] = "John";
person["lastName"] = "Doe";
person["age"] = 46;
var x = person.length; // person.length will return 0
console.log(x);
var y = person[0]; // person[0] will return undefined
console.log(y);