I have two objects which I am comparing. I have an array of objects, and I am trying to see if the array contains a certain object. I think it should be finding it, but it is not. Here is the object in the array:
and here is the object I am looking for:
I am using:
if (collection.indexOf(object) !== -1) {
//do something
}
And it returns an index of -1, even though it seems to me that the objects match. Am I missing something here?
try this, if all fields are equals return true
function testContains(arrayOfObject, lookingObject )
var index;
for (index = 0; index < arrayOfObject.length; ++index) {
var o = arrayOfObject[index]);
if(JSON.encode(o)===JSON.encode(lookingObject)) {
return true;
}
}
return false;
}
indexOf() will work only for elementary types like numbers, strings, boolean etc. It does not do deep comparison to match objects.
Something like the following should work:
var found = false;
arr.forEach(function(_object) {
// code to set found to true if _object is what you need
});
// if found is true, your array has your object, else it doesn't
If you can use Lodash (it's really useful and worth it in my opinion) you can use _.find:
_.find(collection, object)
or if you want to only know if the object is present in array, you can do:
_.includes(collection, object)
I optimized #Kaiser'S answer into a one-liner:
var found = obj_list.map(JSON.stringify).indexOf(JSON.stringify(obj)) !== -1;
But, this will only work, if the order of the objects is the same:
The JSON represantation of obj1 = {'a': 1, 'b': 2} wouldn't match obj2 = {'b': 2, 'a': 1}
But if the object you're looking for was copied from the list then the test should work.
Also to take into account, this will only work if the objects in the list are simple objects which can be "stringified".
Related
Is there a vanilla js way of returning null (or nothing) instead of an empty array[]
from Array.prototype.filter when no elements are found?
Some context:
let arr = [1,2,3,1,1]
let itemsFound = arr.filter(e=> e===6)
if(itemsFound){ // always true, []===true
// do something
}
The if will always evaluate to true as filter returns an empty array[].
And an empty array is 'true' in javascript. Of course I can do,
if(itemsFound.length > 0){
// do something
}
But I think just, if(itemsFound){} is neater.
The answer would not require additional js libraries.
Additional context
Coming from an OO background, I found it quite funky that objects and functions
could be treated like Boolean. But felt it was intuitive after getting used to it.
There are times that I would forget that Array.filter returns an empty array [] when no elements are found. And [] === true. This causes unnecessary bugs.
As with the answers and feedback received of now, I don't think this question can be answered except with a new implementation of Array.filter.
With that said, the accepted answer is the closest to what I have in mind.
you can do something like this, if you just want to check if it exists or not
let arr = [1,2,3,1,1]
let itemsFound = arr.filter(e=> e===6).length
console.log(itemsFound);
if(itemsFound){ // always true
// do something
}
or something like this
let arr = [1,2,3,1,1]
let itemsFound = arr.filter(e=> e===6)
itemsFound = (itemsFound.length > 0 ? itemsFound : false);
console.log(itemsFound)
if(itemsFound){ // always true
// do something
}
Or something like this
Array.prototype.isEmpty = function(){
return this.length == 0;
}
let arr = [1,2,3,1,1];
arr.isEmpty();
let itemsFound = arr.filter(e=> e===6)
if(itemsFound.isEmpty()){ // always true
// do something
console.log('OK');
}
You could use the length property of an array and take the value as truthy/falsy value for the condition.
function getValues(array) {
const result = array.filter(e => e === 6);
return result.length ? result : null;
}
console.log(getValues([1, 2, 3, 1, 1]));
I have this array (below) and I'm trying to check if it has specific values.
var a = [ true, "lipsum" ];
What I need to do, is to check if a[0] is true and if a[1] is "lipsum"
I could check both values separately:
a[0] === true && a[1] === 'lipsum' // true
...to shorten the code a bit, I tried to do this:
a === [ true, 'lipsum'] // false
Why is this code example above false and is there another way to achieve what I'm trying to do?
I could do this:
a.join() === 'true,lipsum' // true
though I can't help but feel that there is a better way..?
jsfiddle
For only two elements to check the straightforward way seems best, but I assume you want to do this for maintenance reasons because eventually you may have several conditions to check (not just two). If so, you can do something like the following, which seems verbose for only two conditions, but as you start adding more it would be more reasonable, so here's an example with 5 conditions to check:
// set a constant somewhere for your truth condition
var COND = [1, 'a', 5, 'b', 0];
// check `a` against the constant array using `every` (Thanks Bergi)
if (a.every(function(v, i){ return COND[i] === v; })) {
// all array elements the same
}
Each array is a separate object, so the equality operator cannot be used to compare them. Assuming that you have a strict comparison of known arguments to do, the first method you use is the best.
If you have another array of arguments that the original array must contain, you must use a loop, although you could abstract it:
Array.prototype.contains = function (array) {
for (var x = 0; x < array.length; x++) {
if (this.length < x || this[x] !== array[x]) {
return false;
}
}
return true;
}
http://jsfiddle.net/q5DvG/1/
The code is very simple and I would be expecting true however it returns false
var markets = ["AB", "CD"];
console.log("AB" in markets);
I think you're meaning if (markets.indexOf('AB') !== -1). in essentially checks if the test is a property of the object, not if an element is contained within the array.
For more information, look at Array.indexOf vs. the in operator.
Because in looks up property names, not values. Your property names are the array indices.
From MDN's page on the in operator:
The in operator returns true if the specified property is in the specified object.
prop A string or numeric expression representing a property name or array index
Note a property name or array index. The in operator does not search for property values, but for property names. In this case, the property names are 0 and 1, so 0 in markets will return true.
You should use indexOf, in browsers that support it, and shim it in those that don't.
Because in is meant for objects, not arrays. If you want to reliably do this you have to search through each element in the array:
for( var i=0, l=markets.length; i<l; i++ ){
if( markets[i] === 'AB' ){
// do something
}
}
The following will work, which is what you're thinking:
var markets = { AB: 1, CD: 1 };
console.log( "AB" in markets );
In only works when you are using an object, not an array. So this will work:
var markets = {
AB: 'AB',
CD: 'CD'
};
'AB' in markets; // true
As said in won't help you in this case.
I guess you'll have to write a searching function.
Here's one:
function inArray(ArrObj, Search){
var exists = false;
for (var i = 0; i < ArrObj.length; i++){
if (ArrObj[i] == Search){
return true;
var exists = true;
break;
}
else if ((i == (ArrObj.length - 1)) && (!exists)){
if (ArrObj[i] != Search){
return false;
}
}
}
}
I think you want something like this, console.log(markets[0]);
If I want to enumerate the properties of an object and want to ignore prototypes, I would use:
var instance = { ... };
for (var prop in instance) {
if (instance.hasOwnProperty(prop)) {
...
}
}
What if instance only has one property, and I want to get that property name? Is there an easier way than doing this:
var instance = { id: "foobar" };
var singleMember = (function() {
for (var prop in instance) {
if (instance.hasOwnProperty(prop)) {
return prop;
}
}
})();
Maybe Object.keys can work for you. If its length returns 1, you can use yourObject[Object.keys[0]] to get the only property of the object. The MDN-link also shows a custom function for use in environments without the keys method1. Code like this:
var obj = {foo:'bar'},
kyz = Object.keys(obj);
if (kyz.length === 1){
alert(obj[kyz[0]]); //=> 'bar'
} else {
/* loop through obj */
}
1 Some older browsers don't support Object.keys. The MDN link supplies code to to make it work in these browsers too. See header Compatibility in the aforementioned MDN page
Shortest form:
instance[Object.keys(instance)[0]];
ES6+ function:
let first = v => v[Object.keys(v)[0]];
Use the function:
first({a:'first', b:'second'}) // return 'first'
var foo = {bar: 1};
console.log(Object.keys(foo).toString());
which will print the string
"bar"
Though my answer is downvoted, it's still worth to know that there is no such thing as order of keys in javascript object. Therefore, in theory, any code build on iterating values can be inconsistent. One approach could be creating an object and to define setter which actually provides counting, ordering and so on, and provide some methods to access this fields. This could be done in modern browsers.
So, to answer you question, in general you approach is still most closs-browser. You can iterate using lodash or any other modern framework wich will hide "hasOwnProperty" complexity from you. As of August'15 Object.keys can be accepted as cross-browser and universal. After all IE8 happened years ago. Still there are some cases when you just don't wont store all set of keys in array. But I'd go with Object.keys - it's more flexible compared to iteration.
Unfortunately, there is no, "list properties" function built in, and there certainly isn't a "getFirstProperty" (especially since there is no guarantee that any property will consistently be "first").
I think you're better off writing a function like this one:
/**
* A means to get all of the keys of a JSON-style object.
* #param obj The object to iterate
* #param count maximum length of returned list (defaults to Infinity).
*/
function getProperties( obj, count )
{
if( isNaN( count ) ) count = Infinity
var keys = []
for( var it in obj )
{
if( keys.length > count ) break;
keys.push( it );
}
return keys;
}
Then, you could access the name though:
instance = {"foo":"bar"}
// String() on an array of < 2 length returns the first value as a string
// or "" if there are no values.
var prop = String(getProperties(instance, 1));
This is an old post, but I ended up writing the following helper function based on Object.keys().
It returns the key and value of the first property.
getFirstPropertyKeyAndValue(sourceObject) {
var result = null;
var ownProperties = Object.keys(sourceObject);
if (ownProperties.length > 0) {
if (ownProperties.length > 1) {
console.warn('Getting first property of an object containing more than 1 own property may result in unexpected results. Ordering is not ensured.', sourceObject);
}
var firstPropertyName = ownProperties[0];
result = {key: firstPropertyName, value: sourceObject[firstPropertyName]};
}
return result;
}
Answers in here all good, and with the caveat that the order may be unreliable (although in practice it seems the order the properties are set tends to stay that way), this quick and dirty method also works:
var obj = {foo: 1, bar: 2};
for(var key in obj) {
//you could use key here if you like
break;
}
//key now contains your first key
or a shorter version should also do it:
for(var key in obj) break;
//key now contains your first key
I'm using a JS array to Map IDs to actual elements, i.e. a key-value store. I would like to iterate over all elements. I tried several methods, but all have its caveats:
for (var item in map) {...}
Does iterates over all properties of the array, therefore it will include also functions and extensions to Array.prototype. For example someone dropping in the Prototype library in the future will brake existing code.
var length = map.lenth;
for (var i = 0; i < length; i++) {
var item = map[i];
...
}
does work but just like
$.each(map, function(index, item) {...});
They iterate over the whole range of indexes 0..max(id) which has horrible drawbacks:
var x = [];
x[1]=1;
x[10]=10;
$.each(x, function(i,v) {console.log(i+": "+v);});
0: undefined
1: 1
2: undefined
3: undefined
4: undefined
5: undefined
6: undefined
7: undefined
8: undefined
9: undefined
10: 10
Of course my IDs wont resemble a continuous sequence either. Moreover there can be huge gaps between them so skipping undefined in the latter case is unacceptable for performance reasons. How is it possible to safely iterate over only the defined elements of an array (in a way that works in all browsers and IE)?
Use hasOwnProperty within for ... in to make sure that prototype additions aren't included:
for (var item in map)
if (map.hasOwnProperty(item)) {
// do something
}
There are three issues:
You should not use for...in to iterate arrays.
You are using the wrong data type for your requirements.
You are not using for...in correctly.
If you want to have something like a hash table then use a plain object:
var map = {};
map[123] = 'something';
map.foo = 'bar';
// same as map['foo'] = 'bar';
//...
It looks like an array, but it is not. It is an object with property 123. You can use either dot notation obj.key (only if the key is a valid identifier - 123 would not be valid so you have to use the following notation) or array notation obj['key'] to access object properties.
It seems that an object would be a more appropriate data structure.
But even then you should make a call to hasOwnProperty (every time you use for...in):
for(var key in obj) {
if(obj.hasOwnProperty(key)) {
//do something
}
}
This checks whether a property is inherited from the prototype (it will return false then) or is truly an own property.
Use the EcmaScript 5 builtin Object.keys, and on non ES5 browsers, define it thus:
Object.keys = function (o) {
var keys = [];
var hasOwnProp = Object.prototype.hasOwnProperty;
if (Object.prototype.toString.call(o) === '[object Array]') {
for (var k in o) {
if (+k === (k & 0x7fffffff) && hasOwnProp.call(o, k)) {
keys[keys.length] = k;
}
}
keys.sort(keys, function (a, b) { return a - b; });
} else {
for (var k in o) {
if (hasOwnProp.call(o, k)) {
keys[keys.length] = k;
}
}
}
return keys;
};
1) use an object like already suggested, it is by far the best solution.
2) if you for some reason need to use an array - don't be scared looping over it with
for(var i, len = arr.length;len < i;i++)
it's very very fast.
3) don't use $.each or similar methods if you want performance - they create a new callstack for every iteration, which is a huge overhead.
Don't use an array. Use an object hash instead
var map = {};
map[key] = value;
...
for (var key in map) {
do something to map[key]
}
You can't do a lot without actually doing a check to see if the value is undefined and then doing operation a or operation b. It would be better to use a predicate to determine if the value is undefined:
x = $.grep(x, function(v, i) { return (typeof(v) != "undefined"); });
There isn't. The only way would be to omit the items from the collection completely, any solution you come up with would still have to do a test on each element for the value.
You could come up with different methods of adding the items key/value to object literals or what have you, but you would still need to omit undefined entries if you do not wish to enumerate over them.