FOR LOOP in Angular Service NOT Working - While Loop Works - javascript

I've worked around this problem with a while loop
but thought I'd explain it here - because it seems odd
I tried iterating through a string in a service using a for loop, but cannot get it to work
When service defined like this
.service('xtratxt', function()
{
var x = 0;
var a = "";
this.convert = function(srctxt)
{
this.a = "";
this.x = 0;
for (this.x=0; this.x++; this.x<srctxt.length)
{
this.a = ans + "X";
}
return ans;
};
})
if I call this in my controller with
$scope.newvalu = xtratxt.convert("Hello");
I should get back a string of X's Eg XXXXX
Instead I get an empty string ""
If I change to a while loop - no problems works a treat
Anyone know why ?
I get no errors in the console either.
AFAIK it doesn't seem to enter the for loop at all

this.convert = function (srctxt) {
var a = "", x = 0, ans = '';
for (x = 0; x < srctxt.length; x++) {
ans += "X";
}
return ans;
};
Shorter version
var str = 'abcde';
str.replace(/\w/gi, 'X');

Related

Having issues converting string to int using parseInt() function

function largestNumber(n) {
let output = "";
var toInt = parseInt(output);
for (let i = 1; i <= n; i++){
output = output + "9";
}
return output;
};
I dont know exactly how to get this to return an integer. I keep getting null, or no output. I have tried
return output.toInt;
var toInt = output.parseInt();
var toInt = output.parseInt(output);
var toInt = output.parseInt("output");
var toInt = parseInt(output);
var toInt = parseInt(output,10);
and a few other various ideas that I dont remember by this point xD.
the help is greatly appreciated!
EDIT
Thanks for the help guys I found the problem in my code was the
var toInt = parseInt(output);
needed to come after the loop and then call
return toInt;
However, Barmar (I hope I spelled your name right) has a much cleaner effective solution.
Your current code always attempts to parse an integer from output, but you always initialize output to an empty string right before the parse, so you get no int as a result.
You need to wait until output has been built up to its final value before you use parseInt().
function largestNumber(n) {
let output = "";
for (let i = 1; i <= n; i++){
output = output + "9";
}
return parseInt(output);
}
console.log(largestNumber(5));
console.log(largestNumber(15));
But really, this can be done in a much simpler way based on what your logic is currently doing:
function largestNumber(n) {
return parseInt("9".repeat(n));
}
console.log(largestNumber(5));
console.log(largestNumber(15));
Javascript statements are executed in the order they're written in the function. So you need to call parseInt() after you do all the concatenations, not before.
function largestNumber(n) {
let output = "";
for (let i = 1; i <= n; i++){
output = output + "9";
}
var toInt = parseInt(output);
return toInt;
};
Although there's not really a good reason to use a string in the first place, you can do this all with arithmetic:
function largestNumber(n) {
result = 0;
for (let i = 1; i <= n; i++) {
result = result * 10 + 9;
}
return result;
}
console.log(largestNumber(5));
Or even more simply:
function largestNumber(n) {
return Math.pow(10, n) - 1;
}
console.log(largestNumber(5));
console.log(largestNumber(15));

In angular updating one variable inexplicably updates another

I am using angular and plotly to plot either the raw data or a moving average. I have the moving average working but I am running into an issue with assigning variables. I retrieve an array of user objects which each have an x and y key with arrays associated with them.
$scope.init=function(){
$rootScope.page='companyResults';
$scope.isPlotlyDone = false;
$scope.moving = false;
var refresh = function () {
incidentService.dayWiseTripsByUser(...).then(function (plotArray){
$scope.unaffectedPlot = plotArray;
$scope.movingAveragePlot = allMoving(plotArray);
console.log($scope.unaffectedPlot[0].y);
console.log($scope.movingAveragePlot[0].y);
});
};
refresh();
}
Im that code block, I would expect that $scope.unaffectedPlot[0].y and $scope.movingAveragePlot[0].y would have different arrays since I ran the latter through the following set of functions. The curious thing is that both $scope variables are synced, so if I run the second through allMoving the unaffectedPlot variable also gets smoothed and neither get synced obviously if I don't call allMoving. What am I missing about Angular? What is a good way to have a moving average work with a toggle? My plan is to show one variable or the other depending on if a button is clicked.
var d3_numeric = function(x) {
return !isNaN(x);
}
var d3sum = function(array, f) {
var s = 0,
n = array.length,
a,
i = -1;
if (arguments.length === 1) {
// zero and null are equivalent
while (++i < n) if (d3_numeric(a = +array[i])) s += a;
} else {
while (++i < n) if (d3_numeric(a = +f.call(array, array[i], i))) s += a;
}
return s;
};
var movingWindowAvg = function (arr, step) {
return arr.map(function (_, idx) {
var wnd = arr.slice(idx - step, idx + step + 1);
var result = d3sum(wnd) / wnd.length; if (isNaN(result)) { result = _; }
return result;
});
};
var allMoving = function(pltArray) {
var movingArray = [];
pltArray.forEach(function(plot){
var oneMoving = plot;
oneMoving.y = movingWindowAvg(plot.y, 5);
movingArray.push(oneMoving);
});
return movingArray;
}
This actually isn't an angular issue. I had to test it some since I didn't see what was going on either.
When you wrote
oneMoving.y = blah
you were actually altering the contents of plot for each element and in turn altering the contents of plotArray unintentionally (since plot is an object)
So you are only creating a reference variable when you say 'var onMoving = plot' )
To outright solve your problem you can clone plot but that isn't so clean of a process
One easy yet dirty way is
JSON.parse(JSON.stringify(obj))
from this thread
I threw together a shotty example that captures what was going wrong for you
var array = [{one:1, two:2},{one:1, two:2},{one:1, two:2}],
copyArray = array,
newArr = doStuff(array)
function doStuff(a) {
var otherNewArr = []
a.forEach(function(ae) {
var aVar = ae
aVar.one = 5
otherNewArr.push(aVar)
})
return otherNewArr
}
console.log(copyArray,newArr)
And to fix it just replace
var aVar = ae
with
var aVar = JSON.parse(JSON.stringify(ae))

indexOf() : is there a better way to implement this?

EDIT
Thank you guys, and i apologize for not being more specific in my question.
This code was written to check if a characters in the second string is in the first string. If so, it'll return true, otherwise a false.
So my code works, I know that much, but I am positive there's gotta be a better way to implement this.
Keep in mind this is a coding challenge from Freecodecamp's Javascript tree.
Here's my code:
function mutation(arr) {
var stringOne = arr[0].toLowerCase();
var stringTwo = arr[1].toLowerCase().split("");
var i = 0;
var truthyFalsy = true;
while (i < arr[1].length && truthyFalsy) {
truthyFalsy = stringOne.indexOf(stringTwo[i]) > -1;
i++
}
console.log(truthyFalsy);
}
mutation(["hello", "hey"]);
//mutation(["hello", "yep"]);
THere's gotta be a better way to do this. I recently learned about the map function, but not sure how to use that to implement this, and also just recently learned of an Array.prototype.every() function, which I am going to read tonight.
Suggestions? Thoughts?
the question is very vague. however what i understood from the code is that you need to check for string match between two strings.
Since you know its two strings, i'd just pass them as two parameters. additionally i'd change the while into a for statement and add a break/continue to avoid using variable get and set.
Notice that in the worst case its almost the same, but in the best case its half computation time.
mutation bestCase 14.84499999999997
mutation worstCase 7.694999999999993
bestCase: 5.595000000000027
worstCase: 7.199999999999989
// your function (to check performance difference)
function mutation(arr) {
var stringOne = arr[0].toLowerCase();
var stringTwo = arr[1].toLowerCase().split("");
var i = 0;
var truthyFalsy = true;
while (i < arr[1].length && truthyFalsy) {
truthyFalsy = stringOne.indexOf(stringTwo[i]) > -1;
i++
}
return truthyFalsy;
}
function hasMatch(base, check) {
var strOne = base.toLowerCase();
var strTwo = check.toLowerCase().split("");
var truthyFalsy = false;
// define both variables (i and l) before the loop condition in order to avoid getting the length property of the string multiple times.
for (var i = 0, l = strTwo.length; i < l; i++) {
var hasChar = strOne.indexOf(strTwo[i]) > -1;
if (hasChar) {
//if has Char, set true and break;
truthyFalsy = true;
break;
}
}
return truthyFalsy;
}
var baseCase = "hello";
var bestCaseStr = "hey";
var worstCaseStr = "yap";
//bestCase find match in first iteration
var bestCase = hasMatch("hello", bestCaseStr);
console.log(bestCase);
//worstCase loop over all of them.
var worstCase = hasMatch("hello", worstCaseStr);
console.log(worstCase);
// on your function
console.log('mutation bestCase', checkPerf(mutation, [baseCase, bestCaseStr]));
console.log('mutation worstCase', checkPerf(mutation, [baseCase, worstCaseStr]));
// simple performance check
console.log('bestCase:', checkPerf(hasMatch, baseCase, bestCaseStr));
console.log('worstCase:', checkPerf(hasMatch, baseCase, worstCaseStr));
function checkPerf(fn) {
var t1 = performance.now();
for (var i = 0; i < 10000; i++) {
fn(arguments[1], arguments[2]);
}
var t2 = performance.now();
return t2 - t1;
}

Javascript Function to split and return a value from a string

I am trying to grab a certain value. I am new to javascript and I can't figure out why this is not working.
If I parse "kid_2" I should get "kostas". Instead of "Kostas" I always get "02-23-2000". So I must have a logic problem in the loop but I am really stuck.
function getold_val(fieldname,str){
var chunks=str.split("||");
var allchunks = chunks.length-1;
for(k=0;k<allchunks;k++){
var n=str.indexOf(fieldname);
alert(chunks[k]);
if(n>0){
var chunkd=chunks[k].split("::");
alert(chunkd);
return chunkd[1];
}
}
}
var test = getold_val('kid_2','date_1::02-23-2000||date_2::06-06-1990||kid_1::George||kid_2::Kostas||');
alert(test);
A regex may be a little more appealing. Here's a fiddle:
function getValue(source, key){
return (new RegExp("(^|\\|)" + key + "::([^$\\|]+)", "i").exec(source) || {})[2];
}
getValue("date_1::02-23-2000||date_2::06-06-1990||kid_1::George||kid_2::Kostas||","kid_2");
But if you want something a little more involved, you can parse that string into a dictionary like so (fiddle):
function splitToDictionary(val, fieldDelimiter, valueDelimiter){
var dict = {},
fields = val.split(fieldDelimiter),
kvp;
for (var i = 0; i < fields.length; i++) {
if (fields[i] !== "") {
kvp = fields[i].split(valueDelimiter);
dict[kvp[0]] = kvp[1];
}
}
return dict;
}
var dict = splitToDictionary("date_1::02-23-2000||date_2::06-06-1990||kid_1::George||kid_2::Kostas||","||","::");
console.log(dict["date_1"]);
console.log(dict["date_2"]);
console.log(dict["kid_1"]);
console.log(dict["kid_2"]);​
This works, here's my fiddle.
function getold_val(fieldname,str) {
var chunks = str.split('||');
for(var i = 0; i < chunks.length-1; i++) {
if(chunks[i].indexOf(fieldname) >= 0) {
return(chunks[i].substring(fieldname.length+2));
}
}
}
alert(getold_val('kid_2', 'date_1::02-23-2000||date_2::06-06-1990||kid_1::George||kid_2::Kostas||'));
The issue with your code was (as #slebetman noticed as well) the fact that a string index can be 0 because it starts exactly in the first letter.
The code is almost the same as yours, I just didn't use the second .split('::') because I felt a .substring(...) would be easier.
There are two bugs. The first error is in the indexOf call:
var n = str.indexOf(fieldname);
This will always return a value greater than or equal to 0 since the field exists in the string. What you should be doing is:
var n = chunks[k].indexOf(fieldname);
The second error is in your if statement. It should be:
if(n >= 0) {
...
}
or
if(n > -1) {
...
}
The substring you are looking for could very well be the at the beginning of the string, in which case its index is 0. indexOf returns -1 if it cannot find what you're looking for.
That being said, here's a better way to do what you're trying to do:
function getold_val(fieldName, str) {
var keyValuePairs = str.split("||");
var returnValue = null;
if(/||$/.match(str)) {
keyValuePairs = keyValuePairs.slice(0, keyValuePairs.length - 1);
}
var found = false;
var i = 0;
while(i < keyValuePairs.length && !found) {
var keyValuePair = keyValuePairs[i].split("::");
var key = keyValuePair[0];
var value = keyValuePair[1];
if(fieldName === key) {
returnValue = value;
found = true;
}
i++;
}
return returnValue;
}

Javascript variable stays undefined

I have a problem with this script, something is going wrong.
Rnumer stays undefined.This script should return and write all uneven digits from the random number list. Can someone tell me what I do wrong. Thanks in advance
var Rnumber = new Array();
for (i = 0; i<= 100;i++)
{
Rnumber[i] = Math.ceil(Math.random()*101);
// document.write(Rnumber[i] + "<br/>");
}
function unevenAndDivisible(Rnumber)
{
var remainder = new Array();
for (i = 0; i<= 100; i++)
{
remainder = parseInt(Rnumber[i])%2;
}
return remainder;
}
document.write(unevenAndDivisible());
Changed to
var Rnumber = new Array();
for (i = 0; i<= 100;i++)
{
Rnumber[i] = Math.ceil(Math.random()*101);
// document.write(Rnumber[i] + "<br/>");
}
function unevenAndDivisible(Rnumber)
{
var remainder = new Array();
for (i = 0; i<= 100; i++)
{
remainder[i] = Rnumber[i]%2;
}
return remainder;
}
document.write(unevenAndDivisible(Rnumber));
but now i get the result :
0,1,0,0,1,0,0,0,1,1,0,0,1,0,1,1,1....
I simply want maybe I asked it wrong the first time, to write al uneven numbers from the random list of Rnumbers
Then I need to divide that through 7 and return that.
EDIT
Allmost all problems are clear , thanks everyone for that.
Their is still one question left:
In this code below it only take the first uneven value from remainder and I want that it takes all values that are uneven to the next if statement to check %7.
Maybe you see the problem better if you run it for youreself
var Rnumber = new Array();
for (i = 0; i<= 100;i++)
{
Rnumber[i] = Math.ceil(Math.random()*101);
}
function unevenAndDivisible()
{
var remainder = [];
var answer = [];
for (i = 0; i<= 100; i++)
{
if (Rnumber[i]%2 !== 0)
{
remainder.push(Rnumber[i]);
for (c = 0; c <= remainder.length;c++)
{
if (remainder[c]%7 == 0)
{
answer.push(remainder[c]);
}
}
}
}
return answer;
}
answer = unevenAndDivisible();
document.write(answer);
Problem solved , Thanks everyone
You don't need to pass Rnumber to the function, as it's already available in scope:
function unevenAndDivisible()
{
var remainder = [];
for (i = 0; i<= 100; i++)
{
if (Rnumber[i]%2 !== 0) {
remainder.push(Rnumber[i]);
}
}
return remainder;
}
remainder = unevenAndDivisible();
console.log(remainder);
JS Fiddle demo.
Edited in response to question from OP (in comments to question, above):
...can someone explain what this mean: var remainder = [];
Sure, it's array-literal notation, which is equal to: var remainder = new Array();, it's just a little more concise, and I prefer to save myself the typing. I get the impression, from JS Lint, whenever I use var x = new Array(); therein that the above version is generally preferred (since it complains otherwise), but I don't know why.
Either pass Rnumber to the function unevenAndDivisible or omit it from the argument list. Since it is an argument, it has more local scope than the initial declaration of Rnumber.
Your problem is the line
function unevenAndDivisible(Rnumber)
You are passing in Rnumber in as an argument, but when you call unevenAndDivisible()
you are not passing it it.
Consequently for the body of the function Rnumber is undefined (cause you passed nothing in)
The following snippet is equivalent to what you wrote nad might explain better
function unevenAndDivisible(xyz)
{
var remainder = new Array();
for (i = 0; i<= 100; i++)
{
remainder = parseInt(xyz[i])%2;
}
return remainder;
}
then called as
unevenAndDivisible(undefined)
to fix it remove the argument from the call definition
i.e. define it as
function unevenAndDivisible()
1 - you is not defining the Rnumber value that's function argument.
2 - in loop, you're defining remainder to divised value of ranumber and is not saving in array; try:
change:
remainder = parseInt(Rnumber[i])%2;
to
remainder[i] = parseInt(Rnumber[i])%2;
var array = [],
i = 100;
while (i--) {
var random = Math.random()*i|0;
if(random % 2)
array.unshift(random);
}
alert(array);

Categories

Resources