Is indexOf slower than trying to index an object? - javascript

I don't know much at all about performance. But, if someArray.includes(someString) has to search the whole array, would trying to find an index of an object be more direct (and thus faster, and also a bit less code)?
// create an array of number strings
const arr = Array(100).from(n => n.toString());
// find whether a string is in the array
const isStringInArr_includes_true = arr.includes("50"); // true
const isStringInArr_includes_false = arr.includes("500"); // true
// instead of creating an array, create an object with the array items as keys
// EDIT: actually you can just use the array itself
// and look up the string as a key
const isStringInArr_lookup_true = !!arr["50"]; // !!("50") === true
const isStringInArr_lookup_false = !!arr["500"]; // !!(undefined) === false
Obviously this would only work with an array of strings.

Related

Array of objects and i want to return true if any key value pair in the object is duplicate

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)

how to add different array item values into single array element?

i have an array like [x/0/2 , x/0/3 , y/3/1 , x/1/1 , x/0/3 , x/1/2],
i need to convert the elements range like [x/0/2-3 , y/3/1 , x/1/1-2]
Please give some suggestion for this.
Use reduce to iterate over the array and create an object grouped by the element root, then use Object.entries to pull out the correct information from the object.
const arr = ['x/0/2', 'x/0/3', 'y/3/1', 'x/1/1', 'x/0/3', 'x/1/2'];
const out = arr.reduce((acc, c) => {
// `split` out the separate parts of the element
const [ root1, root2, index ] = c.split('/');
// We'll use the first two parts as the object key
const key = `${root1}/${root2}`;
// If the key doesn't already exist create an empty
// array as its values
acc[key] = acc[key] || [];
// To prevent duplicates only add an index if it
// isn't already in the array
if (!acc[key].includes(index)) acc[key].push(index);
// Return the accumulator for the next iteration
return acc;
}, {});
// Then iterate over the object entries with `map`
const result = Object.entries(out).map(([ key, values ]) => {
// Return the joined up value
return `${key}/${values.join('-')}`;
});
console.log(result);
If I understand your question, you could create an array within the array to hold the range of values. Checking if the position in the array is an actual array let’s you know there are values that span a range within.
Example:
var values = [x/01, [x/20, x/21, x/22], x/03]
You could also create an object that could accomplish something similar depending on your needs.

How to find existence of an array in a set?

Since set in Javascript is able to take object, including arrays, how do I find the existence of an array list in a set?
I tried the following code:
var sello = new Set();
sello.add(["a","b"])
console.log(sello.has(["a","b"])) // outputs false
I'm assuming
sello.has(["a","b"])
should have output true since I've added the exact array in the set sello. Am I missing out some falsy truthy thing or any logical error?
Note:
I'm not looking to match only the character "a" and/or "b", I'm
looking to match the whole array ["a","b"].
I'm looking to match the array. I just need the content to be the
same, the elements doesn't have to be the same order.
What you're trying to do won't work because in Javascript you can't compare arrays like that, even if they have the same values. This is because arrays are reference types, not value types, and for reference types Javascript determines whether they are equal or not based on whether they are referencing the same object (i.e. the same place in memory). For instance, just try:
console.log(['a','b'] == ['a','b']); // false
Despite having the same values, each array is a new reference, so they are not equal to each other.
In contrast, the comparison in the code below does involve arrays referencing the same object on both sides of the equation:
let a = ['a','b'];
console.log(a == a); // true
And therefore:
let sello = new Set();
sello.add(a);
console.log(sello.has(a)); // true
To remedy this, you'll want to create a function that compares arrays based on their values. You can first check if the arrays have the same length. If not, then they're not equal. You can then loop through the items in each and see if any are different for any given position. If so, they're not equal. Otherwise, assuming you're dealing with a flat array of primitive values (no nested objects of reference type), then the arrays are equal. This is what I do in 'isEqual' below:
function isEqual(x,y) {
if (x.length != y.length)
return false;
for (let i in x)
if (x[i] != y[i])
return false;
return true;
}
Test it if you like:
console.log(isEqual(['a','b'],['a','b'])); // true
Now, unfortunately, Set.has() doesn't accept a function, so we can't use it with isEqual. But you can just loop through the values of the set. If creating a one-liner is the goal, the best way I have found to do this is to convert the set to an array and use the some method. some accepts a function that evaluates each row, and if it returns true for any row, then the result is true, else false.
console.log(
[...sello].some(item => isEqual(item, ['a','b']))
);
// true
In JavaScript, Arrays are Objects, and no two separate Objects are ever considered equal.
MDN shows the same error with a standard object:
var set1 = new Set();
var obj1 = {'key1': 1};
set1.add(obj1);
set1.has(obj1); // returns true
set1.has({'key1': 1}); // returns false because they are different object references
The easiest way to use .has with an Object (such as an Array) is to get a reference to the Object, like:
let sello = new Set();
let myArray = ["a","b"];
sello.add(myArray);
console.log(sello.has(myArray)); // outputs true
If you can't get a reference to the Array, you'll probably need to check each Array in the Set by iterating through the Array and comparing each element individually.
You could do this more concisely, but this explicit example clarifies the process:
// Declares and populates the Set
let sello = new Set();
sello.add( ["a", "c"] );
sello.add( ["a", "b"] );
sello.add( ["b", "c"] );
// Tests the `setHasArray` function
let result = setHasArray(sello, ["a", "b"]);
console.log(`result: ${result}`);
// Defines the `setHasArray` function
function setHasArray(theSet, arrayToMatch){
// Creates a flag
let isMatch = false;
// Iterates through the Set
for (let member of theSet){
// Logs the Array we're about to compare elements of
console.log("comparing:", member);
// Makes sure this member is an Array before proceeding
if(Array.isArray(member)){
// Tentatively sets the flag to `true`
isMatch = true;
// Iterates through the Array, comparing each value
arrayToMatch.forEach( (_, index) => {
// Logs the comparison for the current value
console.log(
member[index]
+ (member[index] === arrayToMatch[index] ? " === " : " !== ")
+ arrayToMatch[index]
);
// Even one non-matching element means the Array doesn't match
if(member[index] !== arrayToMatch[index]){
console.log("Rats! Looked like a possible match there for a second.");
isMatch = false;
}
});
// Logs a successful match for the current member of the Set
if(isMatch){
console.log("Found a match!")
// Stops checking Arrays lest the flag get reset and give us a false negative
break;
}
}
}
// Returns our result
return isMatch;
}
(See .forEach on MDN if you're not familiar with this method.)

Javascript map through array to make another array of objects

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 };
})
)

Is it possible to use array iteration methods on ES6 Set instances?

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.

Categories