My api response looks like this:
id: (...)
user_id: (...)
symptoms: "Sore throat, Headache"
id: (...)
user_id: (...)
symptoms: "Anorexia (Loss of appetite), Shortness of breath (Difficult in breathing), Myalgias (Muscle pains), Sore throat, Headache"
I am trying to match a users symptoms to existing symptoms categories. A user can have upto 14 symptoms. I keep getting an error of Cannot read property 'slice' of undefined when i split and slice the array to get individual symptoms and match them.
When i try to put a default value for the object if a user has less than 14 symptoms, the error persists.
My code:
getSymNum (symp, c) {
var counter = 0
for (var xc in c) {
var symp1 = c[xc].symptoms.split(',')[0]
var symp2 = c[xc].symptoms.split(',')[1].slice(1)
var symp3 = c[xc].symptoms.split(',')[2].slice(2)
var symp4 = c[xc].symptoms.split(',')[3].slice(3)
var symp5 = c[xc].symptoms.split(',')[4].slice(4)
var symp6 = c[xc].symptoms.split(',')[5].slice(5)
if (symp3 !== undefined){
console.log("hello ha")
}
if (symp1 === symp) {
counter++
} else if (symp2 === symp) {
counter++
} else if (symp3 === symp) {
counter++
} else if (symp4 === symp) {
counter++
} else if (symp5 === symp) {
counter++
} else if (symp6 === symp) {
counter++
}
}
return counter
},
You can optimize the check by using array/string methods like contains() or indexOf():
etSymNum (symp, c) {
var counter = 0
for (var xc in c) {
if(c[xc].symptoms.indexOf(symp) !== -1){
counter++;
}
}
return counter
},
Related
I have an object productCounts
[{provisioned=2.0, product=str1, totalID=1.0},
{product=str2, provisioned=4.0, totalID=3.0},
{provisioned=6.0, product=str3, totalID=5.0}]
I have an array uniqueProduct
[str1, str2, str3, str4]
I am then looping a dataset to get the totalID count, add it to the product's totalID but if it doesn't exist, push it to the object.
var countID = 0;
uniqueProduct.forEach(
currentproduct => {
countID = 0;
for (var i = 0; i < shtRng.length; ++i) {
if (shtRng[i][ProductCol].toString() == currentproduct) { // && shtRng[i][IDcol].toString().length>4){
countID++;
}
}
if (countID == 0) {
return;
}
console.log(currentproduct + ": " + countID);
}
)
This works perfectly to return the countID per product in uniqueProduct
Rather than logging the result, I would like to add it to the object like this... If the current unique product is not in the productCounts object, add it.
let obj = productCounts.find((o, i) => {
if (o.product == currentproduct) {
productCounts[i] = { product: currentproduct, totalID: productCounts[i].totalID+countID, provisioned: productCounts[i].provisioned };
return true;
} else {
productCounts.push({ product: currentproduct, totalID: countID, provisioned: 0 });
return true;
}
});
In my head, this should work but it appears to skip some records or add the product multiple times. How do I add to the object correctly?
Expected output is the object to be something similar to:
[{provisioned=2.0, product=str1, totalID=35.0},
{product=str2, provisioned=4.0, totalID=8.0},
{provisioned=6.0, product=str3, totalID=51.0},
{provisioned=6.0, product=str4, totalID=14.0}]
The argument to find() is a function that returns a boolean when the element matches the criteria. The if statement should use the result of this, it shouldn't be in the condition function.
let obj = productCounts.find(o => o.product == currentProduct);
if (obj) {
obj.totalId += countID;
} else {
productCounts.push(productCounts.push({ product: currentproduct, totalID: countID, provisioned: 0 });
}
BTW, your life would be easier if you used an object whose keys are the product names, rather than an array of objects. You can easily turn the array of objects into such an object:
let productCountsObj = Object.fromEntries(productCounts.map(o => [o.product, o]));
if (currentProduct in productCountsObj) {
productCountsObj[currentProduct].totalID += countID;
} else {
productCountsObj[currentProduct] = { product: currentproduct, totalID: countID, provisioned: 0 };
}
I'm trying to make function that will return next or previous item in array, based on parameter "direction".
For example I have array = ['ferrari', 'bmw', 'merc', 'bugatti'] and I want my my function to return 'bugatti' IF currentPointer = 'ferrari' and direction = 'left'
nextPrev(array,direction,currentPointer)
In php we have function next() which moves the internal pointer ... but I don't know how to do it in javascript ...
Try Something like this.
Using the numerical locations of the array and conditionally cycle through:
var array = ['ferrari', 'bmw', 'merc', 'bugatti'];
var returnedElement = nextPrev(array, "left", "ferrari");
// Show Returned Value (Console)
console.log(returnedElement);
function nextPrev(array, direction, currentPointer) {
var arraySize = array.length - 1;
var currentIndex = array.indexOf(currentPointer);
if (direction === "left") {
// Decrease array by one
if (currentIndex == 0) {
// Return Previous (Max Array)
return array[arraySize]
} else {
return array[currentIndex - 1]
}
} else if (direction === "right") {
// Increase array by one
if (currentIndex == arraySize) {
// Go to zero position
return array[0]
} else {
return array[currentIndex + 1]
}
} else {
console.log("Use either 'left' or 'right'");
}
}
The basic idea would be:
function nextPrev(array, direction, currentPointer) {
var index = array.indexOf(currentPointer);
if (direction=="left") {
return array[index == 0 ? array.length-1 : index-1];
} else if (direction=="right") {
return array[index == array.length-1 ? 0 : index+1];
} else {
// default action or throw error
}
}
You can reorganize this a bit:
function nextPrev(array, direction, currentPointer) {
var index = array.indexOf(currentPointer);
var len = array.length;
if (direction=="left") {
index--;
} else if (direction=="right") {
index++
} else {
// default action or throw error
}
return array[(index + len) % len];
}
You might want to add a check that array.indexOf returns a valid index (in case currentPointer contains something not in array).
You can write something like this:
function makeDirectionalIterator(array){
var currIndex = 0;
return {
nextPrev: function(direction){
if(direction === 'left') {
return currIndex < array.length-1 ?
{value: array[++currIndex], done: false} :
{done: true};
}
else {
return currIndex > 0 ?
{value: array[--currIndex], done: false} :
{done: true};
}
},
current: function() {
return { value: array[currIndex] };
}
}
}
Then you can use it like the following
var itr = makeDirectionalIterator(array);
itr.current().value;
itr.nextPrev('left').value;
itr.nextPrev('left').done;
I'm tearing my hair out about a Syntax Error: Unexpected Identifier that I can't figure out. I know what the error means, but as far as I can tell there's nothing wrong.
I've posted the entirety of the script I'm using; what the code is meant to do is allow a user to step through a replay of a gomoku-like game one move at a time. The game data is stored in a csv file that has a row for every move and contains multiple games. Games are identified by an index value.
var replayArray = [],
rawData=[[]];
function importData(matchID,gI) {
var dataPromise = $.ajax({
url:"./data/" + matchID + ".csv",
dataType: 'text'
})
dataPromise.then(function(data) {
rawData = data;
rawData = String(rawData);
rawData = rawData.split(/\n/);
for (h = 0; h < rawData.length; h++){
rawData[h] = String(rawData[h]).split(",");
}
}).done(function(data){
dataToArray(gI,actionReplayKeydown);
})
}
function dataToArray(gI,cb) {
var f = 0;
var g = 0;
for (var i = 0; i < rawData.length; i++) {
var turnArray = [];
if (parseInt(eval(rawData[i][1])) === gI) {
turnArray[0] = colorToNumber(eval(rawData[i][5]));
turnArray[1] = parseInt(eval(rawData[i][6]));
replayArray[g] = turnArray;
g++;
} else {
doNothing();
}
}
cb(replayArray);
}
The dataToArray function is where the problem occurs, in the line
if (parseInt(eval(rawData[i][1])) === gI) {
I think dev tools has been indicating the problem occurs at rawData[i][1], but rawData is a two dimensional array and the indexing should work fine (the first column of rawData contains the game index, and I want all rows where the value of the game index equals the index of the queried game).
The rest of the code follows but is not afaik problematic.
function colorToNumber(inputColor) {
if (inputColor === "B" ) {
return 0
} else {
return 1
}
}
function actionReplay(inputArray) {
addStone(parseInt(inputArray[f][1]),parseInt(inputArray[f][0]));
f++;
$('#whiteLastMove').remove();
$('#blackLastMove').remove();
if ((f+1)===inputArray.length){
$(document).off('keyup').on('keyup',function(e){
if (e.keyCode === 32) {
clearBoard();
createTiles(M,N);
replayArray = [];
rawData="";
}
});
}
}
function actionReplayKeydown() {
$(document).off('keyup').on('keyup',function(e) {
if (e.keyCode === 13) {
actionReplay(replayArray);
evaluateWin(0);
evaluateWin(1);
} else if (e.keyCode === 32) {
clearBoard();
createTiles(M,N);
replayArray = [];
rawData="";
} else {
doNothing();
}
});
}
function playReplay(matchID,gI) {
openCurtain(doNothing);
importData(matchID,gI);
}
I'm sure I'm missing something obvious, but I'm just not figuring it out on my own.
The issue is that there is a js syntax error in the value of rawData[i][1]. If you use your debugger you can see the value and check whether it's valid js for eval to execute.
Given the following obj:
var inputMapping = {
nonNestedItem: "someItem here",
sections: {
general: "Some general section information"
}
};
I'm writing a function to get that data by passing in a string "nonNestedItem" or in the nested case "sections.general". I'm having to use an eval and I was wondering if there was maybe a better way to do this.
Here is what I have so far and it works okay. But improve!
function getNode(name) {
var n = name.split(".");
if (n.length === 1) {
n = name[0];
} else {
var isValid = true,
evalStr = 'inputMapping';
for (var i=0;i<n.length;i++) {
evalStr += '["'+ n[i] +'"]';
if (eval(evalStr) === undefined) {
isValid = false;
break;
}
}
if (isValid) {
// Do something like return the value
}
}
}
Linky to Jsbin
You can use Array.prototype.reduce function like this
var accessString = "sections.general";
console.log(accessString.split(".").reduce(function(previous, current) {
return previous[current];
}, inputMapping));
Output
Some general section information
If your environment doesn't support reduce, you can use this recursive version
function getNestedItem(currentObject, listOfKeys) {
if (listOfKeys.length === 0 || !currentObject) {
return currentObject;
}
return getNestedItem(currentObject[listOfKeys[0]], listOfKeys.slice(1));
}
console.log(getNestedItem(inputMapping, "sections.general".split(".")));
You don't need to use eval() here. You can just use [] to get values from an object. Use a temp object to hold the current value, then update it each time you need the next key.
function getNode(mapping, name) {
var n = name.split(".");
if (n.length === 1) {
return mapping[name];
} else {
var tmp = mapping;
for (var i = 0; i < n.length; i++) {
tmp = tmp[n[i]];
}
return tmp;
}
}
Receiving the above error in reference to the line for ( var i = 0; i < base.contacts.length; i++) { and can't figure out how to resolve. Below is the relevant code section
synckolab.addressbookTools.createTBirdObject = function (base, cards) {
var card = null;
if (base.type === "contact") {
card = Components.classes["#mozilla.org/addressbook/cardproperty;1"].createInstance(Components.interfaces.nsIAbCard);
} else if (base.type === "maillist") {
card = Components.classes["#mozilla.org/addressbook/directoryproperty;1"].createInstance(Components.interfaces.nsIAbDirectory);
card.isMailList = true;
} else {
return null;
}
// for a mailing list add the entries
if (base.type === "maillist") {
card.dirName = this.getCardProperty(base, "DisplayName");
if (this.haveCardProperty(base, "NickName")) {
card.listNickName = this.getCardProperty(base, "NickName");
}
if (this.haveCardProperty(base, "Notes")) {
card.description = this.getCardProperty(base, "Notes");
}
// fill the list
for ( var i = 0; i < base.contacts.length; i++) {
var listCard = cards.get(this.getUID(base.contacts[i]));
card.addressLists.appendElement(listCard, false);
}
} else {
// go through all elements of base
for ( var field in base) {
// skip our own stuff TODO: handle mailing lists!
if (field !== "type" && field !== "synckolab" && field !== "ts" && field !== "contacts" && field !== "isMailList") {
// copy the property from base to card
this.setCardProperty(card, field, this.getCardProperty(base, field));
}
}
}
return card;
};
base is a parameter you hand over to the function which is supposed to be an object having (at least) the following properties:
type
contact
Obviously it is missing the contact property, which again should be an array. So you should take a look at the object which you are handing over to the function.
To fix this problem temporarily you could do:
if (base.contacts){
for ( var i = 0; i < base.contacts.length; i++) {
/*...*/
}
}
However to really fix the problem, you should take a look at the code, where the function is called and examine, how the object which you hand to the function is constructed. Do a
console.log(base);
to take a closer look at the object.