LoDash _.has for multiple keys - javascript

Is there a method or a chain of methods to check if an array of keys exists in an object available in lodash, rather than using the following?
var params = {...}
var isCompleteForm = true;
var requiredKeys = ['firstname', 'lastname', 'email']
for (var i in requiredKeys) {
if (_.has(params, requiredKeys[i]) == false) {
isCompleteForm = false;
break;
}
}
if (isCompleteForm) {
// do something fun
}
UPDATE
Thanks everyone for the awesome solutions! If you're interested, here's the jsPerf of the different solutions.
http://jsperf.com/check-array-of-keys-for-object

I know the question is about lodash, but this can be done with vanilla JS, and it is much faster:
requiredKeys.every(function(k) { return k in params; })
and even cleaner in ES2015:
requiredKeys.every(k => k in params)

You can totally go functional, with every, has and partialfunctions, like this
var requiredKeys = ['firstname', 'lastname', 'email'],
params = {
"firstname": "thefourtheye",
"lastname": "thefourtheye",
"email": "NONE"
};
console.log(_.every(requiredKeys, _.partial(_.has, params)));
// true
We pass a partial function object to _.every, which is actually _.has partially applied to params object. _.every will iterate requiredKeys array and pass the current value to the partial object, which will apply the current value to the partial _.has function and will return true or false. _.every will return true only if all the elements in the array returns true when passed to the function object. In the example I have shown above, since all the keys are in params, it returns true. Even if a single element is not present in that, it will return false.

_(requiredKeys).difference(_(params).keys().value()).empty()
I believe. The key step is getting everything into arrays then working with sets.
or
_requiredKeys.map(_.pluck(params).bind(_)).compact().empty()
Might work.

Assuming that params can have more properties than is required...
var keys = _.keys(params);
var isCompleteForm = requiredKeys.every(function (key) {
return keys.indexOf(key) != -1;
});
Should do the trick.

Related

Adding and Removing Values from JavaScript Array

I have a JavaScript array of numbers. My array is defined like this:
var customerIds = [];
I have a function that is responsible for inserting and removing ids to/from this array. Basically, my function looks like this:
function addOrRemove(shouldAdd, customerId) {
if (shouldAdd) {
if (customerIds.contains(customerId) === false) {
customerIds.push(customerId);
}
} else {
customerIds.remove(customerId);
}
}
This function is basically pseudocode. A JavaScript array does not have a contains or remove function. My question is, is there any elegant way of tackling this problem? The best I can come up with is always looping through the array myself and tracking the index of the first item found.
Thank you for any insights you can provide.
The contains can be achieved with Array.prototype.indexOf, like this
if (customerIds.indexOf(customerId) === -1) {
indexOf function returns -1, if it couldn't find the parameter in the array, otherwise the first index of the match. So, if the result is -1, it means that customerIds doesn't contain customerId.
The remove can be achieved with Array.prototype.indexOf and Array.prototype.splice, like this
var index = customerIds.indexOf(customerId);
if (index !== -1) {
customerIds.splice(index, 1);
}
Similarly, indexOf function returns -1, if it couldn't find the parameter in the array, otherwise the first index of the match. So, if the result is -1, we skip deleteing, otherwise splice 1 element starting from the position index.
You can extend the Array method like below after that you are free to use 'contains' and 'remove'
if (!Array.contains)
Array.prototype.contains = function(a) {
for (var i in this) {
if (this[i] == a) return true;
}
return false
}
if (!Array.remove)
Array.prototype.remove = function(a) {
for (var i in this) {
if (this[i] == a) {
this.splice(i, 1);
}
}
}
Use indexOf and splice
function addOrRemove(shouldAdd, customerId) {
if (shouldAdd) {
if (customerIds.indexOf(customerId) == -1) {
customerIds.push(customerId);
}
} else {
var index = customerIds.indexOf(customerId)
customerIds.splice(index, 1);
}
}
You could definitely use the splice and indexOf as stated by #thefourtheye, yet I would like to provide another approach.
Instead of using an array you could use an object.
var customerIds = {};
//This could also be stated as: var customerIds = new Object(); this is just shorthand
function addOrRemove(shouldAdd, customerId)
{
if(shouldAd)
{
if(!customerIds[customerId])
{
customerIds[customerId] = new Object();
customerIds[customerId].enabled = true;
}
}
else
{
if(customerIds[customerId])
{
customerIds[customerId].enabled = false;
}
}
}
You now can query against the customerIds object for a specific customerId
if(customerIds[customerId].enabled)
Using this method not only provides you with the capability of attaching multiple attributes to a given customerId, but also allows you to keep records of all customerIds after disabling (removing).
Unfortunately, in order to truely remove the customerId, you would need to loop through the object and append each property of the object to a new object except for the one you do not want. The function would look like this:
function removeId(customerId)
{
var n_customerIds = new Object();
for(var key in customerIds)
{
if(key != customerId)
{
n_customerIds[key] = customerIds[key];
}
}
customerIds = n_customerIds;
}
In no way am I stating that this would be the proper approach for your implementation, but I am just providing another method of achieving your goal. There are many equivalent ways to solve your dilemma, and it is solely decided by you which method will best suit your projects functionality. I have personally used this method in many projects, as well as I have used the methods posted by others in many other projects. Each method has their pros and cons.
If you do wish to use this method, I would only suggest doing so if you are not collecting many customerIds and do want a lot of customerData per each customerId, or, if you are collecting many customerIds and do not want a lot of customerData per each customerId. If you store a lot of customerData for a lot of customerIds, you will consume a very large amount of memory.

Javascript: Determine if all of the elements in the array are keys in the object

I am trying to figure out if all of the elements in an array are keys in the object.
var obj = { name: 'Computer', cost: '$1,000' };
var myArray = [ 'name', 'cost', 'bio' ]; //another example would be var myArray = [];
for(var x = 0; x < myArray.length; x++){
if (myArray[x] in obj)
{
return true;
}
}
How can I check if all of the elements in an array are keys in the object?
Do it the other way around. If you find someone in the array who is NOT in the object then you return false. If you reach the end of the loop then you return true because all the keys were in the object.
Depending on what you want, this might do the trick:
function hasKeys(obj, keys) {
for (var i=0; i != keys.length; ++i) {
if (!(keys[i] in obj))
return false;
}
return true;
};
One subtlety you need to ask yourself: do you want to know if the object has the keys directly (i.e. not somewhere in its prototype stack?) If so, then replace keys[i] in obj with obj.hasOwnProperty(keys[i])
function hasKeys(obj, keys) {
return keys.every(Object.prototype.hasOwnProperty.bind(obj));
}
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/every states, "The every method executes the provided callback function once for each element present in the array until it finds one where callback returns a falsy value (a value that becomes false when converted to a Boolean). If such an element is found, the every method immediately returns false. Otherwise, if callback returned a true value for all elements, every will return true. callback is invoked only for indexes of the array which have assigned values; it is not invoked for indexes which have been deleted or which have never been assigned values" (emphasis mine).
Array.some() makes for a clean solution.
// object in question
var obj = { ... };
// keys that need to be present in the object
var keys = [ ... ];
// iterate through the whitelist until we find a key that doesn't exist in the object. If all exist, that means Array.some() is false.
var valid = !keys.some(function(key) {
return !obj.hasOwnProperty(key);
});
An alternative solution would be using a similar concept, but with Array.every(). It is to note that this will generally be slower because it always has to touch every element in the whitelist.
// iterate through the whitelist, making sure the object has each key.
var valid = keys.every(obj.hasOwnProperty);
This problem can be expressed in terms of set inclusion: does the set of property keys completely include the array of required keys? So we can write it as
includes(Object.keys(obj), arr)
So now we just need to write includes.
function includes(arr1, arr2) {
return arr2.every(function(key) {
return contains(arr1, key);
}
}
For contains, we could use Underscore's _.contains, or just write it ourselves:
function contains(arr, val) {
return arr.indexOf(val) !== -1;
}
If we are interested in conciseness at the possible expense of readability, we could shorten our definition of includes to use Function#bind instead of the anonymous function:
function includes(arr1, arr2) {
return arr2.every(contains.bind(0, arr1));
}
Now we have functions we can use for other things, instead of mixing up the two different aspects of the problem--the keys of an object, and set inclusion. If we really want to write an all-in-one function, it becomes the somewhat more readable:
function hasMany(obj, arr) {
return arr.every(_.contains.bind(0, Object.keys(obj));
}
If we want more readability, like we were writing a novel:
function object_has_required_keys(object, required_keys) {
var object_keys = Object.keys(object);
function key_is_present(key) {
return object_keys.indexOf(key) !== -1;
}
return required_keys.every(key_is_present);
}
Underscore's _.intersection
If we're lazy (or smart), we could use Underscore's _.intersection to implement includes:
function includes(arr1, arr2) {
return _.intersection(arr1, arr2).length === arr2.length;
}
The idea is to take the intersection, and if the first array includes the second entirely, then the intersection will contain all the elements of the second array, which we can check by comparing their lengths.
Using ES6 sets
Thinking ahead to ES6, we could implement include using its sets, which ought to be faster:
function includes(arr1, arr2) {
var set = new Set(arr1);
return arr2.every(Set.prototype.has.bind(set));
}

JavaScript: Compare the structure of two JSON objects while ignoring their values

I use a Node.js based mock server for specifying and mocking API responses from a backend. It would greatly help to have some kind of check if both backend and frontend comply with the specification. In order to do that, I need some kind of method of comparing the structure of two JSON Objects.
For example those two objects should be considered equal:
var object1 = {
'name': 'foo',
'id': 123,
'items' : ['bar', 'baz']
}
var object2 = {
'name': 'bar',
'items' : [],
'id': 234
}
Any ideas how I would go about that?
This is an elegant solution. You could do it simple like this:
var equal = true;
for (i in object1) {
if (!object2.hasOwnProperty(i)) {
equal = false;
break;
}
}
If the two elements have the same properties, then, the var equal must remain true.
And as function:
function compareObjects(object1, object2){
for (i in object1)
if (!object2.hasOwnProperty(i))
return false;
return true;
}
You can do that using hasOwnProperty function, and check every property name of object1 which is or not in object2:
function hasSameProperties(obj1, obj2) {
return Object.keys(obj1).every( function(property) {
return obj2.hasOwnProperty(property);
});
}
Demo

Referencing index of an Object within an Object using something equivelant Object.indexOf

I'm surprised that I can't find an answer to this question on StackOverflow (maybe I'm not searching right).
But basically I'm curious to know if there is something similar to the Array.indexOf() method, but for objects. That is, an efficient method of returning the index(es) of a value within an existing Object.
For example, say I have an object:
var obj = { prop1: "a", prop2: "b", prop3: "c", prop4: "a" };
Now I want to find the index(es) that contain "a", it would be nice to do a obj.indexOf("a") and have it return something like ["prop1", "prop4"]
But this doesn't seem to be an implemented method for objects.
Alternatively, I know I can create a function:
function indexOf(val, obj){
var indexes = [];
for (var index in obj){
if(!obj.hasOwnProperty(index)) continue;
if(obj[index] == val){
indexes.push(index);
}
}
if(!indexes.length) return false;
else return indexes;
}
indexOf("a", obj); // returns ["prop1","prop4"]
But this kind of feels clunky to iterate over the whole object this way!! Some of the objects I'll be dealing with will be quite huge and the values might be quite large as well.
Is there a better, more efficient way?
If you have a really huge object, you could use a nice weakmap implementation with the complexity of O(1) to store keys per single object. Therefor you have to implement your hash collection, so when setting a key-value pair, you also store the key in the weakmap.
I made also some bench. comparison of this custom HashMap vs RawObject search - jsperf
function HashMap() {
this.__map = new WeakMap;
this.__hash = {};
}
HashMap.prototype = {
set: function(key, value){
this.unset(key);
if (value == null)
return;
this.__hash[key] = value;
var keys = this.__map.get(value);
if (keys == null)
this.__map.set(value, keys = []);
keys.push(key);
},
unset: function(key){
var value = this.__hash[key];
if (value) {
var keys = this.__map.get(value),
index = keys.indexOf(key);
keys.splice(index, 1);
}
this.__hash[key] = void 0;
},
get: function(key){
return this.__hash[key];
},
getKeys: function(value){
return this.__map.get(value);
}
};
WeakMap uses Object.defineProperty method in its core. For this reason there are some limitations:
browsers: IE9+
Objects as Values in above HashMap example, because they are used as Keys in WeakMap Collection
But this approach makes a huge performance boost, as there is no need to iterate over the object, to look for a specific value.

How to determine if object is in array [duplicate]

This question already has answers here:
How do I check if an array includes a value in JavaScript?
(60 answers)
Closed 29 days ago.
I need to determine if an object already exists in an array in javascript.
eg (dummycode):
var carBrands = [];
var car1 = {name:'ford'};
var car2 = {name:'lexus'};
var car3 = {name:'maserati'};
var car4 = {name:'ford'};
carBrands.push(car1);
carBrands.push(car2);
carBrands.push(car3);
carBrands.push(car4);
now the "carBrands" array contains all instances.
I'm now looking a fast solution to check if an instance of car1, car2, car3 or car4 is already in the carBrands array.
eg:
var contains = carBrands.Contains(car1); //<--- returns bool.
car1 and car4 contain the same data but are different instances they should be tested as not equal.
Do I have add something like a hash to the objects on creation? Or is there a faster way to do this in Javascript.
I am looking for the fastest solution here, if dirty, so it has to be ;) In my app it has to deal with around 10000 instances.
no jquery
Use something like this:
function containsObject(obj, list) {
var i;
for (i = 0; i < list.length; i++) {
if (list[i] === obj) {
return true;
}
}
return false;
}
In this case, containsObject(car4, carBrands) is true. Remove the carBrands.push(car4); call and it will return false instead. If you later expand to using objects to store these other car objects instead of using arrays, you could use something like this instead:
function containsObject(obj, list) {
var x;
for (x in list) {
if (list.hasOwnProperty(x) && list[x] === obj) {
return true;
}
}
return false;
}
This approach will work for arrays too, but when used on arrays it will be a tad slower than the first option.
Why don't you use the indexOf method of javascript arrays?
Check this out: MDN indexOf Arrays
Simply do:
carBrands.indexOf(car1);
It will return you the index (position in the array) of car1. It will return -1 if car1 was not found in the array.
http://jsfiddle.net/Fraximus/r154cd9o
Edit: Note that in the question, the requirements are to check for the same object referenced in the array, and NOT a new object. Even if the new object is identical in content to the object in the array, it is still a different object.
As mentioned in the comments, objects are passed by reference in JS and the same object can exist multiple times in multiple structures.
If you want to create a new object and check if the array contains objects identical to your new one, this answer won't work (Julien's fiddle below), if you want to check for that same object's existence in the array, then this answer will work. Check out the fiddles here and in the comments.
Having been recently bitten by the FP bug reading many wonderful accounts of how neatly the functional paradigm fits with Javascript
I replicate the code for completeness sake and suggest two ways this can be done functionally.
var carBrands = [];
var car1 = {name:'ford'};
var car2 = {name:'lexus'};
var car3 = {name:'maserati'};
var car4 = {name:'ford'};
var car5 = {name:'toyota'};
carBrands.push(car1);
carBrands.push(car2);
carBrands.push(car3);
carBrands.push(car4);
// ES6 approach which uses the includes method (Chrome47+, Firefox43+)
carBrands.includes(car1) // -> true
carBrands.includes(car5) // -> false
If you need to support older browsers use the polyfill, it seems IE9+ and Edge do NOT support it. Located in polyfill section of MSDN page
Alternatively I would like to propose an updated answer to cdhowie
// ES2015 syntax
function containsObject(obj, list) {
return list.some(function(elem) {
return elem === obj
})
}
// or ES6+ syntax with cool fat arrows
function containsObject(obj, list) {
return list.some(elem => elem === obj)
}
try Array.prototype.some()
MDN Array.prototype.some
function isBiggerThan10(element, index, array) {
return element > 10;
}
[2, 5, 8, 1, 4].some(isBiggerThan10); // false
[12, 5, 8, 1, 4].some(isBiggerThan10); // true
You could use jQuery's grep method:
$.grep(carBrands, function(obj) { return obj.name == "ford"; });
But as you specify no jQuery, you could just make a derivative of the function. From the source code:
function grepArray( elems, callback, inv ) {
var ret = [];
// Go through the array, only saving the items
// that pass the validator function
for ( var i = 0, length = elems.length; i < length; i++ ) {
if ( !inv !== !callback( elems[ i ], i ) ) {
ret.push( elems[ i ] );
}
}
return ret;
}
grepArray(carBrands, function(obj) { return obj.name == "ford"; });
I used underscore javascript library to tweak this issue.
function containsObject(obj, list) {
var res = _.find(list, function(val){ return _.isEqual(obj, val)});
return (_.isObject(res))? true:false;
}
please refer to underscore.js documentation for the underscore functions used in the above example.
note: This is not a pure javascript solution. Shared for educational purposes.
You can just use the equality operator: ==. Objects are checked by reference by default, so you don't even need to use the === operator.
try this, just make sure you're using the correct variable reference in the place of car1:
var i, car, l = cars.length;
for (i = 0; i < l; i++)
{
if ((car = cars[i]) == car1)
{
break;
}
else car = null;
}
Edit to add:
An array extension was mentioned, so here's the code for it:
Array.prototype.contains = Array.prototype.contains || function(obj)
{
var i, l = this.length;
for (i = 0; i < l; i++)
{
if (this[i] == obj) return true;
}
return false;
};
Note that I'm caching the length value, as the Array's length property is actually an accessor, which is marginally slower than an internal variable.
I would use a generic iterator of property/value over the array. No jQuery required.
arr = [{prop1: 'val1', prop2: 'val2'}, {prop1: 'val3', prop2: 'val4'}];
objectPropInArray(arr, 'prop1', 'val3'); // <-- returns true
function objectPropInArray(list, prop, val) {
if (list.length > 0 ) {
for (i in list) {
if (list[i][prop] === val) {
return true;
}
}
}
return false;
}
You could try sorting the array based on a property, like so:
carBrands = carBrands.sort(function(x,y){
return (x == y) ? 0 : (x > y) ? 1 : -1;
});
Then you can use an iterative routine to check whether
carBrands[Math.floor(carBrands.length/2)]
// change carBrands.length to a var that keeps
// getting divided by 2 until result is the target
// or no valid target exists
is greater or lesser than the target, and so on, which will let you go through the array quickly to find whether the object exists or not.
try this ,
You can use the JavaScript some() method to find out if a JavaScript array contains an object.
<script>
// An array of objects
var persons = [{name: "Harry"}, {name: "Alice"}, {name: "Peter"}];
// Find if the array contains an object by comparing the property value
if(persons.some(person => person.name === "Peter")){
alert("Object found inside the array.");
} else{
alert("Object not found.");
}
</script>
EDIT 05/18/2022
The most simple way using ES6:
const arrayContainsObject = <T extends Record<string, unknown>>(array: T[], object: T) => {
return array.some(item => Object.keys(item).every(key => item[key] === object[key]))
}
Use like so:
const arr = [{
prop1: 'value1',
prop2: 'value2'
}]
const obj1 = {
prop1: 'value1',
prop2: 'value2'
}
const obj2 = {
prop2: 'value2',
prop1: 'value1'
}
const obj3 = {
prop0: 'value0',
prop1: 'value1'
}
arrayContainsObject(arr, obj1) // true
arrayContainsObject(arr, obj2) // true, even when props are arranged in different order
arrayContainsObject(arr, obj3) // false
Previous answer, don't use (because the order of props in an object needs to be identical)
const arr = [{
prop: 'value'
}]
const obj = {
prop: 'value'
}
arr.some((e) => Object.entries(e).toString() === Object.entries(obj).toString()) // true
i know this is an old post, but i wanted to provide a JQuery plugin version and my code.
// Find the first occurrence of object in list, Similar to $.grep, but stops searching
function findFirst(a,b){
var i; for (i = 0; i < a.length; ++i) { if (b(a[i], i)) return a[i]; } return undefined;
}
usage:
var product = $.findFirst(arrProducts, function(p) { return p.id == 10 });
This function is to check for a unique field.
Arg 1: the array with selected data
Arg 2: key to check
Arg 3: value that must be "validated"
function objectUnique( array, field, value )
{
var unique = true;
array.forEach(function ( entry )
{
if ( entry[field] == value )
{
unique = false;
}
});
return unique;
}
you can use Array.find().
in your case is going to look like this
carBrands.find(function(car){
let result = car.name === 'ford'
if (result == null){
return false;
} else {
return true
}
});
if car is not null it will return the javaScript Object which contains the string 'ford'
The issue with many of the answers here is that they will NOT find an object in an array that is equal to another object. They will only search for an EXISTING object that has a pointer to it in an array.
Quick fix using lodash to see if ANY equal object is in an array:
import _ from 'lodash';
_.find(carBrands, car1); //returns object if true, undefined if false
Working Plunker using this method: https://plnkr.co/edit/y2YX9o7zkQa2r7lJ
if its possible to use es6
carBrands.filter(carBrand => carBrand.name === carX.name).length > 0
if it's true there is a similarity
You can convert both the JSON objects to string and simply check if the bigger json contains the smaller json.
console.log(JSON.stringify(carBrands).includes(JSON.stringify(car1))); // true
console.log(JSON.stringify(carBrands).includes(JSON.stringify(car5))); // false
You could also a the findIndex
var carBrands = [];
var car1 = {name:'ford'};
var car2 = {name:'lexus'};
carBrands.push(car1);
if (carBrands.findIndex(f => f.name === car1.name) === -1) {
console.log('not contain')
} else {
console.log('contain')
}
if (carBrands.findIndex(f => f.name === car2.name) === -1) {
console.log('not contain')
} else {
console.log('contain')
}

Categories

Resources