How to check the properties of an object equal to some value? - javascript

in the code below I want to print the values of "years_of_experience" which is less than 34 and birthplace which is equal to "texas". But I'm not getting how to write the statement correctly
var employees = [
{
name1:'jacob',
age2 : 23,
date_of_join : 23/03/2013,
years_of_experience : 12,
birth_place: "virginia"
},
{
name2:'sheldon',
age2 : 34,
date_of_join :2/03/2013,
years_of_experience : 15,
birth_place: "lisbon"
},
{
name3:'johnny',
age3 : 25,
date_of_join :29/03/2013,
years_of_experience : 13,
birth_place: "texas"
}];
employees.forEach(function(a) {
console.log(a);
});
for(var i = 0;i <= employees.length;i++)
{
if(employees[i]!= -1)
{
console.log("gotcha");
if(employees.hasOwnProperty === years_of_experience) < 34 || (employees.hasOwnProperty(birth_place) === "teaxs")
{
//here i want to print the values of
// "years_of_experience" which is less than 34 and birthplace which is equal to
// "texas".But i'm not getting how to write the statement for that become m new to
// javascript and even m not sure i've written the conditional statement right,
// please correct it and help me..
}
}
}

Try this
if(employees[i].years_of_experience < 34 || employees[i].birth_place === "teaxs")

Like this
var years = employees[i]["years_of_experience"];
var POB = employees[i]["birth_place"];
if (years < 34 || POB === "texas") {
document.getElementById("idOfSomeTag").innerHTML = "Years:" years +", POB"+POB;
// or console.log("years",years,"Pob",POB);
}

Firstly, you misspelled 'texas'
hasOwnProperty() is a method, not a property and also it doesn't pull the value from a property, it simply returns a boolean of whether it has or does not have that property.
You may want something like the following
for (var i = 0; i < employees.length; i++) {
if (employees[i].hasOwnProperty("years_of_experience") && employees[i].hasOwnProperty("birth_place")) {
if (employees[i].years_of_experience < 34 || employees[i].birth_place === "texas") {
console.log("Year of Experience: \n" + employees[i].years_of_experience + "\nBirth Place: " + employees[i].birth_place);
}
}
}
jsFiddle : Check your console.
You should also change your "date_of_join" into a string if that's the way you want to store dates. Right now you are getting a very obscure decimal value.
var employees = [{
...
date_of_join: "23 / 03 / 2013",
...
}, {
...
date_of_join: "2 / 03 / 2013",
...
}, {
...
date_of_join: "29 / 03 / 2013",
...
}];

Related

JavaScript: Get average object in array?

I'm trying to think of a way to make this code simple, with the smallest amount of loops and variables, but I'm having trouble.
I want to get the average object in the array 'numbers', based on the 'value'. I feel that there must be a mathematical way to get the average without finding the closest average in another loop.
Currently I have this mess:
var numbers = [
{ value: 41 },
{ value: 19 },
{ value: 51 },
{ value: 31 },
{ value: 11 }
];
// Find average:
var sum = 0;
for (var i = 0; i < numbers.length; i++) {
sum += numbers[i].value;
}
var average = sum / numbers.length;
// Find closest object to average:
var match, difference;
for (var j = 0; j < numbers.length; j++) {
const diff = Math.abs(average - numbers[j].value);
if (difference === undefined || diff < difference) {
difference = diff;
match = numbers[j];
}
}
// Print junk:
console.log("AVERAGE NUMBER: " + average);
console.log("CLOSEST OBJECT: " + match);
console.log("CLOSEST NUMBER: " + match.value);
I need to retrieve the object because it contains other information that I need to use.
Any help would be highly appreciated!
At least you need two loops for getting the average and the closest item, because you need to visit all items in the first run and you do not have the possibillity to store in advance which item has the closest value.
You could get first the average and then reduce the closest value with the object.
var numbers = [{ value: 41 }, { value: 19 }, { value: 51 }, { value: 31 }, { value: 11 }, { value: 30 }],
average = numbers.reduce((sum, { value }) => sum + value, 0) / numbers.length,
closest = numbers.reduce((a, b) =>
Math.abs(average - a.value) <= Math.abs(average - b.value)
? a
: b
);
console.log(average);
console.log(closest);

Have user vote only once per topic but they can change their mind

I need help with logic. I have "useful" and "notUseful" button on reviews across my site. I made it so that when user clicks on them I get an object like usefulness: { usefulResult: 1, notUseful: 0, useful: 1 }, so every time the user clicks a button the appropriate property gets incremented. and usefulResult is just useful - notUseful.
The main problem I'm having now is that I want one user to only be able to make one vote for a review but they could change their mind later. I know how to find out which user is doing the voting. but I can't think of the logic so the count wont increment more than 1 vote.
This is bad:
bad: user could keep clicking on notUseful button and the notUseful button counter keeps rising.
Info: The usefulness object has the count for all the users for a specific review so it could already be populated from previous data . so lets say the data was originally usefulness: { usefulResult:-2 , notUseful: 5, useful: 3}, and a new user votes useful it should be usefulness: { usefulResult:-1 , notUseful: 5, useful: 4}, if he then changes his mind and votes notUseful the object should change to usefulness: { usefulResult:-3 , notUseful: 6, useful: 3}.
Im working with mongoose and and express. I tried A bunch of stuff. Here's some stuff I'm working with. It might not make sense to you. Don't know what is wrong with me. Some stuff at the beginning is for other functionality. some of the stuff I previously tried is in comments.
Reviews.findOne({companyName: comp , user : userId}).populate({
path : "user",
model : "Anon"
})
.then(function(returnedReview){
console.log("returnedReview", returnedReview)
// var returnedModel = new Reviews
// returnedReview.usefulness = {}
var mapped = returnedReview.userWhoVoted.toObject().map(function(e) {return e.userWhoVotedId.toString()})
if(mapped.indexOf(app.locals.user._id.toString()) == -1){
console.log("typeof app.locals.user.id---", typeof app.locals.user._id.toString())
mapped.push(app.locals.user._id.toString())
}
var index = mapped.indexOf(app.locals.user._id.toString())
console.log("--------INDEX----------", index)
console.log("mapped User that voted?? --" , mapped)
var checkForuserWhoVotedId= returnedReview.userWhoVoted.toObject().some(function(el){
return el.userWhoVotedId.toString() == app.locals.user._id.toString()
})
var checkForWordUseful = returnedReview.userWhoVoted.toObject().some(function(el){
return el.result == "useful" && el.userWhoVotedId.toString() == app.locals.user._id;
})
var checkForWordNotUsefull = returnedReview.userWhoVoted.toObject().some(function(el){
return el.result == "notUseful" && el.userWhoVotedId.toString() == app.locals.user._id;
})
var userWhoVoted = returnedReview.userWhoVoted;
var usefulnessObj = returnedReview.usefulness;
if(userWhoVoted.toObject().length == 0){
userWhoVoted.push({userWhoVotedId : app.locals.user._id.toString(), result : result})
}else if(userWhoVoted.toObject().length > 0 && !checkForuserWhoVotedId) {
userWhoVoted.push({userWhoVotedId : app.locals.user._id, result : result})
}else if(userWhoVoted.toObject().length > 0 && checkForuserWhoVotedId && result == "notUseful" && checkForWordUseful){
if(userWhoVoted[index].result){
var indexed = userWhoVoted[index].result
}
userWhoVoted[index].result = "notUseful"
}else if(userWhoVoted.toObject().length > 0 && checkForuserWhoVotedId && result == "useful" && checkForWordNotUsefull){
if(userWhoVoted[index].result){
var indexed = userWhoVoted[index].result
}
userWhoVoted[index].result = "useful"
}
if(!checkForuserWhoVotedId){
if(result == "useful") usefulnessObj.useful++
if(result == "notUseful") usefulnessObj.notUseful++
userWhoVoted[index].nowUseful = usefulnessObj.useful;
userWhoVoted[index].nowNotUseful = usefulnessObj.notUseful;
console.log("usefulnessObj.useful : ",usefulnessObj.useful, "userWhoVoted[index].nowUseful + 1 : ", userWhoVoted[index].nowUseful + 1)
}else if(checkForuserWhoVotedId){
// console.log("usefulnessObj.useful : ",usefulnessObj.useful, "userWhoVoted[index].nowUseful + 1 : ", userWhoVoted[index].nowUseful + 1)
if(result == "useful" && usefulnessObj.useful + 1 <= userWhoVoted[index].nowUseful ){
usefulnessObj.useful++
// usefulnessObj.notUseful--
}
if(result == "notUseful" && usefulnessObj.notUseful + 1 <= userWhoVoted[index].nowNotUseful ){
usefulnessObj.notUseful++
// usefulnessObj.useful--
}
// if(result == "useful" && usefulnessObj.useful > userWhoVoted[index].nowUseful - 1){
// }
}
// var upperBoundUseful =
// console.log("userWhoVoted[index].result ", indexed, " result: ", result)
// if(indexed !== result){
// if(userWhoVoted[index].result =="useful"){
// returnedReview.usefulness.useful++
// returnedReview.usefulness.notUseful--
// }else if(userWhoVoted[index].result =="notUseful"){
// returnedReview.usefulness.notUseful++
// returnedReview.usefulness.useful--
// }
// }
// if(indexed !== userWhoVoted[index].result)
// if(result == "useful") returnedReview.usefulness.useful++
// if(result == "notUseful") returnedReview.usefulness.notUseful++
returnedReview.usefulness.usefulResult = returnedReview.usefulness.useful - Math.abs(returnedReview.usefulness.notUseful);
// userWhoVoted = []
returnedReview.save(function(err, doc){
if(err) throw err;
if(doc) console.log("doc", doc)
res.send(doc.usefulness)
// res.end()
})
})
.catch(function(err){
console.log(err)
})
// res.end()
}
object returned from save:
doc { _id: 57c760de1e08000300525775,
updatedAt: Wed Sep 07 2016 03:32:29 GMT-0400 (Eastern Daylight Time),
createdAt: Wed Aug 31 2016 18:57:34 GMT-0400 (Eastern Daylight Time),
vote: 'up',
reviewText: 'this sisisfrfr',
company: 57c4f982a82a799432999b63,
companyName: 'comp1',
userType: 'anon',
user:
{ _id: 57c760cf1e08000300525774,
__v: 1,
usefulness: [],
reviews: [ 57c760de1e08000300525775 ] },
__v: 2,
className: '',
createdString: 'We, August 31st 16, 6:57:34 pm',
momented: '6 days ago',
updatedString: 'We, September 7th 16, 3:32:23 am',
userWhoVoted:
[ { nowNotUseful: 0,
nowUseful: 1,
userWhoVotedId: 57cfc275e3ec2c3826ea55a0,
result: 'notUseful' } ],
usefulness: { usefulResult: 1, notUseful: 0, useful: 1 },
statements:
[ { name: 'statement2',
question: 'This is the question for statement2',
result: 6 },
{ name: 'statement3',
question: 'This is the question for statement3',
result: 9 } ] }
It got out of hand.
Alright, so your problem is you only want the user to have 1 vote, and you're looking for a good structure for this? Here is what I would do on a simplified comment structure:
https://jsfiddle.net/WilliamIPark/kuy0d1ec/5/
var review = {
author: '57c760cf1e08000300525774',
content:'Some content',
usefulness: {
useful: [
'57c760cf1e08000300525774',
'57cfc275e3ec2c3826ea55a0'
],
useless: [
'57cfc275e308000300a55a7',
'57c4f982a82a799432999b63',
'57c4f982f82a799400a55a7'
],
total: function() {
return this.useful.length - this.useless.length;
}
}
}
review.usefulness.total() will spit out the calculation, and it will be accurate so long as you keep only 1 instance of the user ids in the "useful" and "useless" arrays.
Obviously, you would then have a couple of functions to:
Add a user ID into the review.usefullness object, to either review.usefullness.useful or review.usefullness.useless.
Check for the user's ID existing already in either review.usefullness.useful or review.usefullness.useless, and add, do nothing, or remove from review.usefullness.useful or review.usefullness.useless depending on the check.

Weird behavior in increment operator

I was playing with javascript trying to create a classic spiral matrix like this one:
01 02 03 04
12 13 14 05
11 16 15 06
10 09 08 07
But when I debugged my code, I noticed something weird:
The matrix array is filling the space [1][x] when j is 0
How is that possible?
What is the explanation for this behavior?
Here is the piece of code:
var draw = function(direction, dim) {
var directions = ['right', 'down', 'left', 'up'];
var __matrix = Array(dim[0]).fill(Array(dim[1]).fill(0));
var fill = {};
fill.right = function(nextIndex, matrix, j, i, value) {
if(value === (dim[0] * dim[1])) { return matrix; }
if(matrix[j][i] === 0) { matrix[j][i++] = value++; }
else { i--; nextIndex++; }
debugger;
return fill[directions[nextIndex]].apply({}, arguments);
}
fill.down = function() { }; //todo
fill.left = function() { }; //todo
fill.up = function() { }; //todo
return fill[direction](directions.indexOf(direction), __matrix, 0, 0, 1);
};
console.log(draw('right', [4,4]));
This has nothing to do with the increment operator. You are writing on the 0 index, it just so happens that every array in your matrix array is the same array reference.
var arr = Array(4).fill(Array(4).fill(0))
//arr[0] === arr[1] === arr[2] === arr[3]
arr[0][0] = 'Hey';
console.log(arr[1][0]) //also 'Hey'
Seems your problem in this line
Array(dim[0]).fill(Array(dim[1]).fill(0));
Array.fill makes shallow copy of the array
When you change one element of the array it will affect to all elements, because it reference to the same object.
See example below:
var matrix = Array(5).fill(Array(5).fill(0));
document.write('<br>before <pre>' + JSON.stringify(matrix) + '</pre>') ;
matrix[1][0] = 1;
document.write('<br>after <pre>' + JSON.stringify(matrix) + '</pre>') ;
It's diffcult to answer such a question without a fiddle, sorry...
I'd try to put some console.log() before and after the indicted statement (matrix[j][i++] = value++;), to understand what's happening...

Javascript: Extra character in concatenated string preventing match with object key

I'm trying to access an object within another object using an object key. I'm concatenating the values of a group of <select> elements to build a string that matches the key. Unfortunately this never works. Here's the code below:
var valueKeyString = "";
$(".keySelector").each(function(){
valueKeyString += $(this).val();
});
if (geoAttrs[selectedGeoAttr].rowCol == "row") {
mapData = rowValueGroups[valueKeyString];
} else if (geoAttrs[selectedGeoAttr].rowCol == "col") {
mapData = colValueGroups[valueKeyString];
}
After trying a good number of things I tested the strings character by character using charCodeAt():
var test1 = valueKeyString;
for (var i = 0, len = valueKeyString.length; i < len; i++) {
test1 += valueKeyString.charCodeAt(i)+" ";
}
if (geoAttrs[selectedGeoAttr].rowCol == "row") {
Object.keys(colValueGroups).forEach(function(group) {
var test2 = group;
for (var i = 0, len = group.length; i < len; i++) {
test2 += group.charCodeAt(i)+" ";
}
console.log(test1);
console.log(test2)
})
mapData = colValueGroups[valueKeyString];
}
My concatenated strings all had an extra character with a charCode of 0 at the point of concatenation. Couldn't figure out why it was there or how to get rid of it using a regEx or str.replace(). Ended up with an ugly but functional solution where I just test the object keys to see if they contain the values from the <select> elements:
var valueKeys = [];
$(".keySelector").each(function(){
valueKeys.push($(this).val());
});
if (geoAttrs[selectedGeoAttr].rowCol == "row") {
Object.keys(colValueGroups).forEach(function(group) {
var groupHasAllKeys = true;
valueKeys.forEach(function(key) {
if (group.indexOf(key) == -1 ) {
groupHasAllKeys = false;
}
});
if(groupHasAllKeys) {
mapData = colValueGroups[group];
}
});
} else if (geoAttrs[selectedGeoAttr].rowCol == "col") {
Object.keys(rowValueGroups).forEach(function(group) {
var groupHasAllKeys = true;
valueKeys.forEach(function(key) {
if (group.indexOf(key) == -1 ) {
groupHasAllKeys = false;
}
});
if(groupHasAllKeys) {
mapData = rowValueGroups[group];
}
});
}
There's got to be a better way, right? What the hell is going on here?
EDIT: rowValueGroups might look something like this:
{
"35_to_44_yearsMale": {
"4654387684": {
"value": 215
},
"4654387685": {
"value": 175
},
"4654387686": {
"value": 687
},
"4654387687": {
"value": 172
}
},
"45_to_54_yearsMale": {
"4654387684": {
"value": 516
},
"4654387685": {
"value": 223
},
"4654387686": {
"value": 54
},
"4654387687": {
"value": 164
}
}
}
valueKeyString should be "45_to_54_yearsMale" or the like.
This is survey data. I'm extracting the rowValueGroups data from the output of a nicolaskruchten/pivottable custom renderer. (Specifically from the pivotData.tree object if you're curious). I'm not looking to alter the pivottable core to change how those keys are formatted, so I just figured I'd concatenate a couple of values from a select element to make it work.
Here's part of the console output from the tests above:
35_to_44_yearsMale51 53 95 116 111 95 52 52 95 121 101 97 114 115 0 77 97 108 101
35_to_44_yearsMale51 53 95 116 111 95 52 52 95 121 101 97 114 115 77 97 108 101
First line is the test done on valueKeyString and the second on one of the keys from rowValueGroups. Note that the initial string looks identical, (the Firefox console actually outputs a little character-not-found square in between "years" and "Male" for the valueKeyString one) but the charCodeAt() turns up that weird 0 character at the point of concatenation.
You have null characters in your string. This regex will remove them:
valueKeyString = valueKeyString.replace( /\0/g, '' )
Reference: Removing null characters from a string in JavaScript
If you identify the char code you can try to replace it using exactly its code:
var valueKeyString = "";
$(".keySelector").each(function(){
valueKeyString += $(this).val();
});
valueKeyString = valueKeyString.replace(new RegExp(String.fromCharCode(0),"g"),'');
Or presuming the string already comes \0-terminated directly from the jquery $(this).val() you can try another approach:
var valueKeyString = "";
$(".keySelector").each(function(){
s = $(this).val();
if ( s.charCodeAt(s.length - 1) == 0 )
s = s.substring(0, s.length - 1);
valueKeyString += s;
});
The above snippet check if the last char of each freshly obtained string from $(this).val() is null-terminated (just to be sure) and remove the last char with substring().
Since you are using jQuery you can try trim():
var valueKeyString = "";
$(".keySelector").each(function(){
valueKeyString += $(this).val().trim();
});

Finding a number in an Array closest to mine [duplicate]

This question already has answers here:
Find the number in an array that is closest to a given number
(7 answers)
Closed 9 years ago.
I am fairly new to javascript and I'm having problems finding the most efficient way to calculate the problem below
I have an array of objects. Each object has a time stamp and a total field. I have a number saved as a variable and I want to loop through the array to find the timestamp of the object with the total field closest to my number.
This is a sorted array so the numbers are always increasing so for example the numbers could look like this:
Jan 125
Feb 150
Mar 200
Apr 275
If the number I have is 205 I would like to get the result Mar back.
They are objects taken from a mongoDb so look something like this
{TimeStamp: "2013-06-24 01:00", Delivered: 464, Queued: 39, Total: 503}
{TimeStamp: "2013-07-02 01:00", Delivered: 485, Queued: 37, Total: 522}
{TimeStamp: "2013-07-05 01:00", Delivered: 501, Queued: 41, Total: 542}
{TimeStamp: "2013-07-08 09:48", Delivered: 501, Queued: 64, Total: 565}
If the list is already sorted on the right field, you can use this code to find the minimum distance in O(n):
var data = [
{total: 125, name: 'Jan'},
{total: 150, name: 'Feb'},
{total: 200, name: 'Mar'},
{total: 275, name: 'Apr'}
];
function getClosest(arr, value)
{
var closest, mindiff = null;
for (var i = 0; i < arr.length; ++i) {
var diff = Math.abs(arr[i].total - value);
if (mindiff === null || diff < mindiff) {
// first value or trend decreasing
closest = i;
mindiff = diff;
} else {
// trend will increase from this point onwards
return arr[closest];
}
}
return null;
}
You keep track of the currently closest object and its corresponding (absolute) difference between the total and the searched value.
You keep updating those two values as long as the difference decreases. When that no longer happens you can return immediately, because you know it will never decrease afterwards.
To use it:
getClosest(data, 200);
I've got this helpful generic function:
function min(ary, key) {
return ary.map(function(x) {
return [key ? key(x) : x, x]
}).reduce(function(m, x) {
return x[0] < m[0] ? x : m;
})[1]
}
It finds a minimal element in the array using key as a comparison function. Applied to your problem:
number = ...
closestTimestamp = min(arrayOfRecords, function(record) {
return Math.abs(number - record.total)
}).TimeStamp;
var numbers = [122,231,323,53];
var myNumber = 200;
var difference = 9999;
var nearest = null;
for (i = 0 ; i < numbers.lenght; i++){
var candidate = numbers[i];
var currentDifference = Math.abs(myNumber - candidate);
if (currentDifference < difference) {
nearest = candidate; difference = currentDifference;
}
}
You can use a binary search for that value. Adapted from this answer:
function nearestIndex(arr, compare) { // binary search, with custom compare function
var l = 0,
r = arr.length - 1;
while (l <= r) {
var m = l + ((r - l) >> 1);
var comp = compare(arr[m]);
if (comp < 0) // arr[m] comes before the element
l = m + 1;
else if (comp > 0) // arr[m] comes after the element
r = m - 1;
else // this[m] equals the element
return m;
}
// now, l == r+1
// usually you would just return -1 in case nothing is found
if (l == arr.length) return r;
if (r == 0) return 0;
if (Math.abs(compare(arr[l])) > Math.abs(compare(arr[r]))) // "closer"
return r;
else
return l;
}
var items = […];
var i=nearestIndex(items, function(x){return x.Total-532;}); // compare against 532
console.log(items[i].TimeStamp);

Categories