Variables equality - javascript

I'm unsure why example 1 don't give the same result as example 2.
Example 1:
var a = [1,6,2,4];
var b = [];
function minT(data){
var d = [];
d = data;
d.sort(function(a, b){return a-b});
return d;
};
b = minT(a)
console.log("b =" + b);
console.log("a =" + a);
Results:
b =1,2,4,6
a =1,2,4,6
Example2:
var a = [1,6,2,4];
var b = [];
function minT(data){
var d = [];
d = data.slice(0,10);
d.sort(function(a, b){return a-b});
return d;
};
b = minT(a)
console.log("b =" + b);
console.log("a =" + a);
Results:
b = 1,2,4,6
a = 1,6,2,4
Why does example 1 affect array a?
How can I write a function minT that does not affect array a. (without a slice inside the function)?

The reason why your first attempt sorts your a array also is because d = data; just copies the object reference, so both variables are pointing to the same location in memory.
When you do d = data.slice(0,10);, you're assigning the result of the slice operation to the d variable, which is a different object in memory than the data variable is pointing to.
Check out this book excerpt on the differences between value vs reference.

In example 1:
You have written d=data. It means that d is pointing to the element data. You have not just copied the values.
Example 2:
You have written d=data.slice(0,10). It actually copies the element of data rather than copying the address of data.
Now, to write the function minT without affecting data, and without using function data.slice(), you just need to replace the line data.slice() with your own simple code to copy element of one array to another.
Here's what I've done :
function minT(data){
var d = [];
for(var i=0;i<data.length;i++)
d[i]=data[i];
d.sort(function(a, b){return a-b});
return d;
};

Related

for loop function that returns sum [duplicate]

This question already has answers here:
Generating Fibonacci Sequence
(52 answers)
Closed 4 months ago.
I have a sequence that needs to be an output.. which is 8
so what i did (with a help of a friend of course.. bec i'm not smart and have adhd.. is this:
let a = 1;
let b = 1;
let c = a + b;
a = b; // 1
b = c; // 2
c = a + b; // 3
a = b; // a = 2
b = c; // b = 3
c = a + b; // 2 + 3 = 5 c = 5
what i need next, is to make a for loop, that will calculate it to 8 (perform the exact same calc task as above
(a = b and b = c and c = a + b)
to make the function get print an output of 8..
let a = 1;
let b = 1;
let c = a + b;
a = b; // 1
b = c; // 2
c = a + b; // 3
a = b; // a = 2
b = c; // b = 3
c = a + b; // 2 + 3 = 5 c = 5
function calc () {
for (let i=0; i<= ( ? ? ? ? ? ?); i++){
console.log(i);
}
}
calc()
function calc () {
for (let a = 0, b = 1, c = 0; c < 8;) {
c = a + b;
a = b;
b = c;
console.log(c);
}
}
calc();
does it work as you need?
The main idea here: in the loop you can use any variables to set initial state, increment and break condition.
UPDATE
The loop simply repeats what you've done without loop. Let's see where every part of your code goes.
Loop declaration contains 3 parts.
Initialization
let a = 1;
let b = 1;
I just updated a to be 0, not 1. So number 1 will be displayed in your console.
Exit condition.
As you described, loop should end when we reach 8. We increment the values inside the loop and then display it. So condition should be c < 8.
"Increment"
In your case it's
let c = a + b;
a = b; // 1
b = c; // 2
This block is repeated several times and contains more than 1 assignment. So we put it inside the block and leave the "increment" part empty.
It sounds like you're trying to output the Fibonacci sequence (1, 1, 2, 3, 5, 8, 13...) where each number in the sequence is the sum of the two previous numbers.
function calc() {
// We need to hard-code the first two numbers in the sequence to get started
let a = 1;
let b = 1;
console.log(a);
console.log(b);
// If we do 4 loops, the last value printed will be 8
for (let i = 0; i < 4; i++) {
let c = a + b
console.log(c);
// Shift a and b along the sequence
// a gets the value held by b, and b gets the value held by c
a = b
b = c
}
}
calc();
If you want it to only print out 8.
function calc() {
let a = 1;
let b = 1;
for (let i = 0; i < 4; i++) {
let c = a + b
a = b
b = c
}
console.log(b); // Prints 8
}
calc();
Yes, a Fibonacci series - what fun!
Here is a slightly condensed version of it with only two variabes (a and b):
function calc (max) {
for (let a = 0, b = 1; b < max;) console.log(([a,b] = [b,a+b])[1])
}
calc(100);
Update
Here a version that will only return the last two values (for later use in your HTML): the last one below and the first one above the target value max:
function calc (max) {
for (var a = 0, b = 1; b < max;) [a,b] = [b,a+b];
return [a,b];
}
console.log(calc(100));
Sorry for overloading you. I have to admit, I didn't carefully read all the text in your question. In particular your ADHD situation. No worries, I will try to explain what I did now in more detail so you will be able to follow:
1. My loop is set up in a for() loop - like in Alexey's solution:
for (var a = 0, b = 1; b < max;)
This means
that initially the variables a and b will be set upt to contain the values 0 and 1 (the two assignemts are separated by the ,-opertor).
The second part of the for expression (b < max) checks whether bis still below the maximum value max and only then will the loop expression be executed.
A third expression (behind the ;-separator) does not exist.
2. The loop expression ...
[a,b] = [b,a+b]
... makes use of the new ES6 feature of destructuring. It is a shorthand version of the otherwise three separate assignement statements:
tmp = b; // buffer the value of b
b = a+b; // do the sum and re-assign to b
a = tmp; // assign the original value of b to variable a
The ES6 construct is helpful here,
as it buffers the calculated results of the right hand side before assigning it to the array on the left hand side of the equation.
Only then (in the destructuring phase) will the newly calculated values be assigned to the variables a and b.
3. The return value(s)
As I was uncertain as to which value you wanted to have returned from the function I chose to return two values in an array: one below and one above the target value max.
return [a,b];
It is up to you to adapt the return statement to better suit your needs: either return a; or return b;.
4. var instead of let
Please note that I used var a=0, b=1 instead of let a=0, b=1 in the for() loop of my later version, as I needed to access these variables outside the scope of the for() loop. The var defines a variable with function scope (instead of block scope).
I hope that this will help you a little more than my admittedly fairly cryptic first version.
Alternative version (variation)
If you are looking for a function that will retun the n-th value of the Fibonacci series you can do it like this:
function fib (n) {
for (var a = 0, b = 1; n--;) [a,b] = [b,a+b];
return b;
}
// test the function fib with n = 1, ..., 19
for (let i=1; i<20; i++) console.log(`fib(${i}):`,fib(i));

why is this a not defined when it clearly is?

I'm a total newbie, trying to survive my JS assignments. Any help is welcome.
When I run the following code, I get an error message saying "a is not defined." But a is defined.
function name(a, n) {
let a = b;
let b = x;
let c = n;
let b = c;
return c + a;
}
console.log(name(a, n));
a is only defined inside the function.
You are trying to read a (and n) outside the function and pass the resulting values to the function.
The problem is the way you call the function name instead of this console.log(name(a, n)); use this: console.log(name(5, 10));
As #Quentin said, when you pass the variables a and b to the function console log, it has to be defined outside of your function, but you can pass just the values and don't need to define the a and b variable outside the function.
So many problems here...
function name(a, n) {
let a = b; // a is already declared in function's declaration
let b = x; // x has never been declared
let c = n;
let b = c; // b is already declared in Line 3, additionally this line will make b = n
return n + a;
// this would finally become return b + b
// because Line 4: c = n
// and Line 5: b = c
// and Line 2: a = b
}
document.write(name(a,n)); // a and n should contain any value

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))

How do I replace variables with values inside a stringified function (Javascript)?

Consider the following :
var a = 5;
var b = function ()
{
console.log (a + 5);
};
var c = b.toString();
after the above has been executed, c will be equal to :
"function ()
{
console.log (a + 5);
}"
How can I have c be equal to :
"function ()
{
console.log (5 + 5);
}"
instead?
I tried the following :
var a = 5;
var b = function ()
{
console.log ('<%a%>' + 5);
};
var c = b.toString().replace('<%a%>', a);
But the above obviously makes c equal to :
"function ()
{
console.log ('5' + 5);
}"
Is there some other way of achieving this (javascript + RegEx) without using libraries like underscore (with the known template function) ?
Basically I'm trying to come up with a neat function that will convert a function into a string while at the same time replacing all variables (that have a hardcoded value) present in that function with their respective values, without the use of any variables.
Thanks
You can fix your snippet by changing the first argument of .replace:
var a = 5;
var b = function ()
{
console.log ('<%a%>' + 5);
};
var c = b.toString().replace("'<%a%>'", a);
For more generic solution you may need smarter parser with syntactical analysis.

Order of object elements in Firefox (JS enumeration)

The enumeration of JS objects seems to be inconsistent in Firefox.
Code:
var a = {"3":"a", "2":"b", "foo":"c", "1":"d"};
var str = "";
for(var n in a) { str += n + " = " + a[n] + "\n"; }
alert(str);
Result with FF22 on Windows:
1 = d
2 = b
3 = a
foo = c
Result expected (and what I get with FF20 on Linux):
3 = a
2 = b
foo = c
1 = d
How can I keep the Elements in the same order as inserted?
I know the ECMA specification doesn't say how the enumeration should be done, therefore it can't be called a bug. But I need the elements in the order inserted. (Reason: I get a JSON-encoded hash-table which is ordered server-side. Until recently the order was kept, now the whole list is a mess because it's ordered by the keys)
No, you can't get that. The order of keys in object is undetermined and can be anything JS implementation wants.
You can, however, sort the keys:
var a = {"3":"a", "2":"b", "foo":"c", "1":"d"};
var str = "";
for(var n in Object.keys(a).sort(your_sorting_function)) {
str += n + " = " + a[n] + "\n";
}
alert(str);
your_sorting_function should accept two arguments, which effectively will be names of the keys in a object. Then this function should return 0 for identical keys, 1 if the first key is considered "bigger" and -1 otherwise.
Object.keys() does not exist in all the browsers, but there's plenty of implementations that can be found.
For example:
Object.keys = Object.keys || function(o) {
var result = [];
for(var name in o) {
if (o.hasOwnProperty(name))
result.push(name);
}
return result;
};

Categories

Resources