I am wondering about the difference between this:
function doesCodeExist(arrvalidcodes, code) {
var hit = arrvalidcodes.filter(function(item){
return (code === item)
}).map(function(item){
return true;
});
if (hit[0] === true) {
return true;
} else {
return false;
}
}
and this:
function doesCodeExist(arrvalidcodes, code) {
for (var i = 0; i < arrvalidcodes.lenght; i++) {
if (arrvalidcodes[i] === code) {
return true;
}
}
return false;
}
Both codes should do the same thing, simply return true if the code is in the provided array or otherwise return false.
Which is considered the most readable and which is the more efficient way of doing it?
Of course your first code is worse because it allocates various useless arrays and is not readable.
If you want semantic ES5 array methods, use some:
function doesCodeExist(arrvalidcodes, code) {
return arrvalidcodes.some(function(item){
return code === item;
});
}
Of course, for just strict comparison you should use indexOf, or is you want a SameValueZero comparisson use includes.
You could use Array#indexOf
The indexOf() method returns the first index at which a given element can be found in the array, or -1 if it is not present.
function doesCodeExist(arrvalidcodes, code) {
return arrvalidcodes.indexOf(code) !== -1;
}
or with ES6 use Array#includes
Related
I am trying to create a function that would work the same way as the method includes by using two parameters. Right now it only works with methods that would return false, however, true doesn't work and I can't figure out why it doesn't go into the if statement.
function includes(array, value) {
for(let i =0; i < array.length; i += 1) {
if (array[i] === value) {
return true;
} else {
return false;
}
}
}
includes([1,2,3,4,5], 3);
You're returning a result on the very first iteration of the loop, thereby terminating the function before you've checked every element.
You can easily fix this by only returning true if you do find it, and otherwise just continuing the loop, returning false only after the loop if it wasn't found:
function includes(array, value) {
for(let i =0; i < array.length; i += 1) {
if (array[i] === value) {
return true;
}
}
return false;
}
You can use indexOf method from Javascript and do like this:
function includes(array, value) {
return array.indexOf(value) !== -1
}
console.log(includes([1,2,3,4,5], 3));
This is a short and simple solution that also supports IE9 whereas Javascript's includes method doesn't in any IE as per MDN Docs.
Why don't you use includes method in the includes function?
function includes(array, value) {
return array.includes(value)
}
But I don't see what is the point of having a function like that.
If you need a function that will mimic includes method:
function includes(array, value) {
for(e of array) {
if (e == value) return true;
}
return false;
}
Instead of for-of loop, you can use other array methods like find, indexOf, filter, but using for loop is better idea in terms of performance because you can break early. It can be important when you work on huge data.
I have a for/in loop that I would like to know if I'm at the end of. I'm not entirely sure how this would work?
My code is:
for (const key in posts.val()) {
if(posts.val()[key][postId] != undefined) {
found = true;
//do something
} else {
// if at end && found !== true
}
}
Any idea how I would know if I'm at the end of the for/in loop?
Thank you!
There's no built-in functionality for something like that. Assuming the properties don't get mutated when .val() is called, you could call .val() initially to get the object, count up the number of keys (including inherited keys) with for..in, and then use for..in again to iterate and be able to test how close you are to the end of the loop:
const val = posts.val();
let totalKeyCount = 0;
for (const _ in posts.val()) {
totalKeyCount++;
}
let keyIndex = 0;
for (const key in posts.val()) {
keyIndex++;
if(val[key][postId] != undefined) {
found = true;
//do something
} else {
if (keyIndex === totalKeyCount) {
console.log('last iteration');
}
}
}
But, if you don't depend on inherited keys, it would be better to use Object.keys, which returns an array, and upon which array methods can be used.
Assuming you're trying to find a particular value in the object (and on the object itself), you can use .find on Object.values instead:
const foundPost = Object.values(posts.val()).find(item => item[postId] !== undefined);
// if an item[postId], if it exists, will be truthy, simplify to `item => item[postId]`
if (foundPost) {
// do something with the found post
} else {
// all iterations have been completed, and nothing was found
}
Also note that the order of properties iterated on in a for..in loop is not entirely reliable. As MDN says:
A for...in loop iterates over the properties of an object in an arbitrary order (see the delete operator for more on why one cannot depend on the seeming orderliness of iteration, at least in a cross-browser setting).
There's no real notion of end of an object unless you mean the last key to iterate. You can get the object's keys, iterate, and check the index against keys.length-1:
let obj = posts.val();
Object.keys(obj).forEach((k, i, keys) => {
if(obj[k][postId] !== undefined) {
let found = true;
//do something
} else {
let atEnd = (i === keys.length-1);
// if at end && found !== true
}
});
Typically, finding something looks like this:
function isFound(obj, cmpFn) {
let found = false;
for (let k in obj) {
if (cmpFn(obj[k]) === true) {
found = true;
break;
}
}
return found;
}
Or:
function isFound(obj, cmpFn) {
return Object.keys(obj)
.some(k => cmpFn(obj[k]));
}
You should have both keys somewhere, so you can avoid iteration entirely:
let isFound = (id_b in obj[id_a]);
The above works if you don't store empty entries in the table, which is usually desirable.
I'd also recommend using !== over != to avoid coercion and ambiguity.
I have some simple objects in an Array. I want to add new objects to the Array only if they are not already in it, based on an object property.
var o = {text: 'foo'}
var a = [o]
var checkExisting = function (list, obj) {
list.forEach(function(elem) {
if (elem.text === obj) {
return true
}
}
}
checkExisting(a, 'foo')
This doesn't work. I can't figure out why. Any help or alternatives would be great.
Because you can't return value from callback in forEach, you can use for, like this
var checkExisting = function (list, obj) {
for (var i = 0, len = list.length; i < len; i++) {
if (list[i].text === obj) {
return true;
}
}
}
This can be done very similar to how you are but with .every() because .forEach() always returns undefined. So you can't chain it either.
.every() runs a method over every element like .forEach() but if it receives a false value it will abort. Finally if every iteration returns true it will return true to the caller otherwise it will return false.
Because we return false to make it abort when a value is found (so it wont keep iterating), we then have to flip the value it returns before we return it from checkExisting.
So using that you could do something like:
var checkExisting = function (list, obj) {
return !list.every(function(elem) {
return elem.text !== obj;
});
}
Obviously you would have to extend that for error handling if the object doesn't have a property text etc.
See fiddle: http://jsfiddle.net/reLsqhkm/
And docs: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/every
How can test over an object like the array.every() method? Trying to detect if all the terms in a query object are blank before sending it on. Obviously I could just write a little routine in a for loop, but I'm expecting there's a more succinct way of accomplishing this.
// array - works
var queryArr = [ "", "" ];
if(!queryArr.every(function(el, i, arr) { return el == "" } )) {
alert("nothing to search");
}
// object - "undefined is not a function"
var queryObj = { term1: "", term2: "" };
if(!queryObj.every(function(el, i, arr) { return el == "" } )) {
alert("nothing to search");
}
Map can be used call a function on each object in an array.
http://api.jquery.com/jquery.map/
You could implement your own every method this way:
Object.prototype.every=function(evalFunction){
var self=this,
property;
if(typeof evalFunction!=='function')
return evalFunction;
for(property in self){
if(self.hasOwnProperty(property) && !evalFunction(self[property], property, self)){
return false;
}
}
return true;
}
Then you could use the new every method on objects the same way you do with arrays But if you only want to test this once on your code I sugest to use for in loop or robisrob's map solution
I am not sure on the use of indexOf in arrays of objects
The code which is not working is:
if (res.locals.company.companies.indexOf(req.query.companyId) >= 0) return next()
The if condition will always return false.
I also tested in console and it is actually wrong:
>> var zio = { __v: 1,
_id: '50bc0238049a1ff10b000001',
companies:
[ { _id: '50bc01938f164ee80b000001', name: 'Test' },
{ _id: '50bc01ac4e860ee90b000001', name: 'zio' } ],
}
>> zio.companies.indexOf("50bc01938f164ee80b000001")
-1
whereas it should be true.
Should I use any mysterious underscore utility ?
UPDATE/Clarification: my aim is just to check if 50bc01938f164ee80b000001 exists in one of the ids, I don't need to know where it actually is. This is very performance critical!
Nodejs solutions or tips would be amazing!
It's not wrong. That Array does not contain a String like that, but only two Object references. Hence, the result is correctly -1.
To get the index from the Object reference containing the searched string value, we could go like
var index;
zio.companies.some(function( obj, idx ) {
if( obj._id === '50bc01938f164ee80b000001' ) {
index = idx;
return true;
}
});
console.log('index is: ', index);
Based on your ninja edit, if you just want to know whether or not an object ref holding a specific id is contained by that array, use it like
var check = zio.companies.filter(function( obj ) {
return obj._id === '50bc01938f164ee80b000001';
});
if( check.length ) {
console.log('yep');
} else {
console.log('nope');
}
Second edit: If you are really and only after performance, you probably don't want to have any function call overhead in any search. I'd use something like
function inObject(arr, search) {
var len = arr.length;
while( len-- ) {
if(arr[len]._id === search)
return true;
}
}
if( inObject( zio.companies, 'AAA' ) ) {
}
That code outclasses any snippet provided here by a few magnitudes. See Here
You'll need to loop over the elements and check for the _id being equal.
indexOf checks for strict equality, and those objects are of course not equal to that string. (It's the same logic as "hello" === {foo: "hello"}. That will always be false.)
I'm sure with node there's some fancy way to do that, but the bare-JS way is:
var i,
arr = [{foo: 'bar'}, {foo: 'baz'}],
idx = -1;
for (i = 0; i < arr.length; ++i) {
if (arr[i].foo === 'bar') {
idx = i;
break;
}
}
You could also easily turn that into a function:
function indexOf(arr, pred) {
for (var i = 0; i < arr.length; ++i) {
if (pred(arr)) {
return i;
}
}
return -1;
}
That would give you a lot more verbose usage though (and a bit worse performance), but it might also be a bit more flexible if you find yourself needing to do it often.
console.log(indexOf(arr, function(elem) { return elem.foo === 'bar'; });
.indexOf is returning the correct output; your array doesn't have an element with that string. In fact, it's an array holding two object literals. You don't need .indexOf for objects, instead we must make our own function:
var inObject = function( object, val ) {
for (var i in object) { if ( object.hasOwnProperty(i) ) {
if ( obj[i] === val ) {
return true;
}
}
}
return false;
};
>>> inObject( zio.companies[0], '50bc01938f164ee80b000001' );
: true
Your companies seems to be an array of objects (not ids), which has Id as one of the attributes. indexOf function is used to find the index of the matching element. Since you are passing an ID value to search the index, its not finding it as an element on the array hence returning false.
To fix the problem, you have two options:
Iterate the companies element compare the ID value, if matched return true otherwise false.
Use the object with desired id in as argument in the indexOf function. If value is greater than -1, return true otherwise false.