Phrasing a block differently returns different values - javascript

I was testing a few pieces of code out, and two statements that should return the same value return different values.
const arr = [3, 'foo', { bar: 'baz' }, false, 4, 5];
for(var i = 0; i < arr.length; i++) {
i = arr[i]
console.log(i)
}
returns [3, 4, 5], while
const arr = [3, 'foo', { bar: 'baz' }, false, 4, 5];
for(var i = 0; i < arr.length; i++) {
console.log(arr[i])
}
returns [3, 'foo', { bar: 'baz' }, false, 4, 5]
Why?

This is a great example of both the flexibility and pitfalls of imperative programming.
tl;dr you shouldn't be modifying i in you're for loops, and you also shouldn't be using for loops. A better way to iterate over the array is:
arr.forEach(function(item, i) {
console.log(item)
})
Imperative Programming
Copied from Wikipedia: In computer science, imperative programming is a programming paradigm that uses statements that change a program's state.
What does this mean?
In simple terms, whenever you are modifying variables (mutation), you're programming imperatively. For example:
var x = 1;
x = 5;
console.log(x + 5); // you would get 10
However, this can lead to unexpected problems which we can see in your example which is explained pretty well in other answers.
This is why in general, it's a good idea to avoid it (at least in Javascript) even though imperative programming is so convenient. This doesn't mean we always avoid it. Sometimes, programs need to run as efficient as possible, and imperatively modifying variables is the only way to achieve that.
In most cases, we don't need that efficiency if we're iterating (looping) through only a few hundred or even tens of thousands of variables. Our computers are fast enough that the difference in performance is not worth it.
Functional Programming
Functional programming is a great alternative. In practice, it boils down to one simple rule - no side effects. Side effects simply mean mutation, i.e modifying variables.
This avoids bugs that would be introduced in imperative programming since you know that once you initialize a variable, it will always be the same.
Below, I'll outline a pseudo introduction to functional programming and how it relates to your example. If you want to learn more about it, you can find countless resources online. Here's a pretty good article about functional programming with Javascript.
Some examples of functional programming
const x = 5; // we use const do denote x is constant and can't be changed ever
// x = 5 would give us an error!
const y = x + 5
// for (const i = 0; i < 10; ++i) is not functional since i is modified!
How should we loop without for loops? Recursion!
It's almost always good to avoid using for loops in the form of for (var i ...). This is because those loops are based on imperative programming, which we want to avoid if possible.
How do we print all the values of an array?
function printValues(arr, i = 0) {
if (i == arr.length) return; // exit when we reach the end
console.log(arr[i]); // let's call console.log
printValues(arr, i + 1); // do the same thing with the next index of the array
}
What if instead of just printing, we want to double every element in the array and double it? Instead of rewriting the same function, we can generalize this:
function forEach(arr, method, i = 0) {
if (i == arr.length) return;
method(arr[i], i)
return forEach(arr, method, i + 1)
}
// notice that forEach looks exactly like printValues, except now, we can pass in anything we would have passed into a normal for loop
forEach([1,2,3,4,5], function(item, i) {
const x = i * 2
console.log(x);
})
// now back to OP's example, we can use this forEach function
forEach(arr, function (item, i) {
console.log(item)
})
Of course, Javascript has these functions built-in and they are also optimized. So, you can just use the built-in forEach:
arr.forEach(function(item, i) {
console.log(item)
// or console.log(arr[i]);
})
There are other functions to use too other than forEach, these include:
map
filter
reduce
There are more, but these are the fundamental building blocks for iteration on arrays in functional Javascript and are must-haves in your toolkit!

I think second snippet explains itself only the first one needs explanation.
First of all there is no sense to write i = arr[i] inside a loop. It changes the looping number of the element at corresponding index. Which means anything unexpected could happen
What happened in your case is below
In first iteration i is 0 then its changed to 3 due to i = arr[i].
In second iteration i is 4 because last value of i is incremented due to i++. Due to i = arr[i] i becomes 4 the arr[4]
In third iteration i becomes 5 due to increment i++ and due i = arr[i] it remains 5.
In fourth iteration it becomes 6 and loop ends because i < arr.length becomes false
const arr = [3, 'foo', { bar: 'baz' }, false, 4, 5];
for(var i = 0; i < arr.length; i++) {
console.log(`Initial i = ${i}`)
i = arr[i];
console.log(`Final i = ${i}`);
console.log('\n')
}

Related

For loop initializer capture [duplicate]

This question already has answers here:
Explanation of `let` and block scoping with for loops
(5 answers)
let keyword in the for loop
(3 answers)
Closed 2 years ago.
I am quite confused about the closing behaviour of functions declared inside of for loops, in particular about variables defined in initializers:
function createFunctions(){
const functions = []
for(let i = 0; i < 5; i++)
functions.push(() => i);
return functions;
}
const results = createFunctions().map(m => m())
// results: [0, 1, 2, 3, 4]
vs
function createFunctions(){
const functions = []
let i;
for(i = 0; i < 5; i++)
functions.push(() => i);
return functions;
}
const results = createFunctions().map(m => m())
// results: [5, 5, 5, 5, 5]
Since the anonymous arrow function declared in the for loop captures its scope, I would expect both cases to yield [5, 5, 5, 5, 5], since at call time, i's value is 5. The first result however seems to suggest that on each iteration through the loop, i is a different variable. However, if you repeat the test but the initialized variable is an object instead of a number:
function createFunctions(){
const functions = []
for(let obj = {}, i = 0; i < 5; i++)
functions.push(() => obj);
return functions;
}
const results = createFunctions().map(m => m())
// results: [{}, {}, {}, {}, {}]; results[0] === results[1]: true
we can see that all elements in the returned array are referentially equal, and so are not different variables. So it seems that the way that functions close over variables declared in the for loop initializer changes depending on whether the variable is a primitive or not, which sounds preposterous to me.
What am I missing?
So, I went through all the trouble of writing this question, and while researching I found the answer somewhat by accident, so I thought I'd switch this to a self-answer question so that if others encounter the same behaviour, it may be easier to find.
I found the answer here
In loops, you get a fresh binding for each iteration if you
let-declare a variable. The loops that allow you to do so are: for,
for-in and for-of.
Which explains why the objects are equal: we get a new variable which gets assigned to the value of the previous one at the end of the loop. In the case of the object, the new variable is pointing to the same object, which explains the referential equality. It also explains why the first case yields [0, 1, 2, 3, 4]: numbers are values, not references, unlike objects.

benefits of map over for loop in terms of safety [duplicate]

This question already has answers here:
Imperative vs Declarative code [closed]
(3 answers)
Closed 4 years ago.
I have a vague understanding of what does it mean "provide immutability" when talking about using map over for loop. Because calling Array.prototype.map on array does not prevent you from altering original array. Let's say we have single threaded asynchronous program. In these circumstances is there an "immutability" benefit that map provides over for loop?
I can imagine the following code:
function A() {
const arr = [1, 2, 3, 4, 5]
const anotherArr = arr.map((e, i) => {
arr[i] = 'changed'
// here goes some asynchronous code
return e * 2
})
// now arr is ['changed', 'changed', 'changed', 'changed', 'changed']
// and anotherArr is [2, 3, 6, 8, 10]
}
function B() {
const arr = [1, 2, 3, 4, 5]
const anotherArr = []
for (let i = 0, len = arr.length; i < len; i++) {
anotherArr[i] = arr[i] * 2
arr[i] = 'changed'
// here goes some asynchronous code
}
// and again:
// now arr is ['changed', 'changed', 'changed', 'changed', 'changed']
// and anotherArr is [2, 3, 6, 8, 10]
}
I guess that probably in function B anotherArr is created manually before populating. Therefore something in the same scope can alter it before for loop is completed. So my question is: "Is there a benefit of using map over for loop in single threaded asynchronous environment in terms of safety"?
Editing
I rephrase my question: "Is there some kind of immutability that Array.prototype.map function
provides (because it belongs to functional paradigm)".
As I understand now the map function in javascript is not about immutability,
it is about hiding some implementation details (how resulting array is constructed).
So map function is a delclarative way of doing things. for loop is an imperative
way of doing things (which brings more freedom and more responsibility I guess).
map, reduce, filter, forEach, etc.
Methods above, in my mind, is nice for FP(functional programming).
Of course, you can use them instead of normal for loop,
but normal for loop is faster than them(https://hackernoon.com/javascript-performance-test-for-vs-for-each-vs-map-reduce-filter-find-32c1113f19d7).
So in my idea, if your don't care performance, use map, reduce, etc. is elegant and will get lesser and more readable code.

Interview live-coding - Find Second Biggest number in array

Quick meta-info:
I was looking for really right place for this question, there is none on stackoverflow. Still answering this question requires programming experience.
I am senior software engineer and lead node.js developer in company with 250 employees, therefore I am doing technical interviews. I am here only for 2 months, so I do not have that much experience with it (previous company was much smaller, so hiring new backend guy was very rare).
The part of interview is live-coding, usually through skype. I think this is quite important, because some people are really not able to do almost anything.
But there is one thing that bugs me - a lot people failing on task "find second biggest number in array" which I think is very easy.
I usually write them this piece of code with only limitation - dont sort an array and dont use any special functions for arrays:
const _arr = [1, 7, 8, 5, 4, 2];
function findSecondBiggest(arr){
}
console.log(findSecondBiggest(_arr));
And task is to write code into function that finds second biggest number. I thought this would be just "check" question and would be "just do it" for most programmers.
Even the developers that look quite promising are often failing on that. I know that they are under pressure, but I am even trying to guide them, calm them and they have at least 20 minutes (often even 30 as I stay 10 minutes more on the call to give them chance to finish it).
A lot of developers look very promising - they have good experience, knowledge, are able to evaluate why they are using this framework/technology... But are not able to do this one.
I have consulted it with Technical Lead and he says that if they are not able to do this, we should discontinue - as we are looking for the programmers and we are expecting to write code. Also the company is interested for mid to senior level developers.
Is this task really that hard? Or is it a good one that really shows if you can come up with at least simple algorithm and implement it?
I am also accepting the solution where you use two for-cycles when first one finds the biggest number, the second for-cycle finds the second biggest number as it is still O(n).
It's not hard, and it makes you think. I would definitely use this kind of question in an interview. However, I would prepare some guiding questions:
How would you find the largest?
How do you know that a number is the 2nd?
etc...
And here is my lovely solution (test cases stolen from #BrettDeWoody's answer). You can use the the standard way of finding the largest number, and then add in the lowest as well.
const _arr = [1, 7, 8, 5, 4, 2];
function findSecondBiggest(arr){
const r = {};
for(let i = 0; i < arr.length; i++) {
if(r.first === undefined || arr[i] > r.first) {
r.second = r.first;
r.first = arr[i];
} else if (arr[i] !== r.first && (r.second === undefined || arr[i] > r.second)) {
r.second = arr[i];
}
}
return r.second; // for arrays with length under 2, the answer would be undefined
}
console.log(findSecondBiggest([1, 7, 8, 5, 4, 2])); // 7
console.log(findSecondBiggest([1, 0, 0, 0, -1, -2])); // 0
console.log(findSecondBiggest([2, 2, 1, 0, -1, -2, 2])); // 1
console.log(findSecondBiggest([1, 1, 1, 1, 1])); // undefined
console.log(findSecondBiggest([0, 0, 0, 1])); // 0
console.log(findSecondBiggest([1, 2, 3, 4])); // 3
console.log(findSecondBiggest([Infinity, -Infinity])); // -Infinity
console.log(findSecondBiggest([-Infinity, Infinity])); // -Infinity
console.log(findSecondBiggest([1, 2, 3, 4, 5, Infinity])); // 5
console.log(findSecondBiggest([1])); // undefined
Completely agree with smac89's sentiment. As a member of an engineering hiring team, and code mentor, I'm not a fan of interview questions with unrealistic constraints.
Instead of asking a question a candidate will never encounter outside a technical interview, pose a challenging question relevant to what the candidate will be working on, and allow the candidate to demonstrate their knowledge of the language and skills they'll be using.
As a great example, a friend recently shared a frontend interview question - build a simple app without any libraries, within a time constraint.
Using a provided API endpoint (which returned paginated results using a ?page=N query param), the app had to take a user's search, retrieve all the results (which might involve multiple pages of results), sort all the results alphabetically, and display all the results at once. This required knowledge (and more importantly, awareness) of fetch, Promise (and Promise.all), array methods, event listeners, and vanilla JavaScript DOM manipulation.
The candidate could consult any docs, and use any built-in methods as needed. The time constraint allowed enough to time to complete as long as the candidate was somewhat familiar with the built-in JS methods, Fetch API, Promises, etc.
IMO, a near-perfect interview question (for frontend devs at least).
My 2ยข.
And here's my solution to the question which:
Uses ES5
Uses no array methods (other than Array.length)
Handles edge cases like a homogeneous array, array of length 1, etc
function findSecondBiggest(arr, startInd){
let start = startInd || 0;
let largest = arr[start];
let secondLargest = null;
const arrLength = arr.length;
if (start === arrLength - start) {
return null;
}
for (var i = start + 1; i < arrLength; i++) {
largest = arr[i] > largest ? setSecond(largest) && arr[i] : largest;
}
function setSecond(num, check) {
secondLargest = num;
return true;
}
if (secondLargest === null) {
arr[arrLength] = arr[0];
return findSecondBiggest(arr, start + 1);
}
return secondLargest;
}
console.log(findSecondBiggest([1, 7, 8, 5, 4, 2]));
console.log(findSecondBiggest([1, 0, 0, 0, -1, -2]));
console.log(findSecondBiggest([2, 2, 1, 0, -1, -2, 2]));
console.log(findSecondBiggest([1, 1, 1, 1, 1]));
console.log(findSecondBiggest([0, 0, 0, 1]));
console.log(findSecondBiggest([1, 2, 3, 4]));
console.log(findSecondBiggest([Infinity, -Infinity]));
console.log(findSecondBiggest([-Infinity, Infinity]));
console.log(findSecondBiggest([1, 2, 3, 4, 5, Infinity]));
console.log(findSecondBiggest([1]));
In reality, developers will take the path of least resistance. That is, they will sort the array and take the second last element. Less code to write and less thinking involved. A win in my book.
So the question you have to consider is whether you want developers who can remember how to implement this algorithm correctly from scratch (possibly buggy), or the ones who can reuse already existing methods to find the solution in the least amount of time, with nearly negligible time penalty, AND mostly bug free.
I mean when was the last time you wanted to find the second largest element in an array of millions of elements? Most developers will probably just opt for the method I described initially (sorting and take second largest), and leave the optimisation to O(n) for another time if it is found that the code is the bottleneck to any performance issues.
const _arr = [1, 7, 8, 5, 4, 2];
function findSecondBiggest(arr) {
if(arr.length < 2) {
return undefined;
}
var first = arr[0];
var second = arr[1];
if(second > first) {
[first, second] = [second, first];
}
for(var i = 2; i < arr.length; i++) {
var tmp = arr[i];
if(tmp > first) {
[first, second] = [tmp, first];
} else if(tmp > second) {
[first, second] = [first, tmp];
}
}
return first != second ? second : undefined;
}
console.log(findSecondBiggest(_arr));
No, I wouldn't say this is an exactly hard question. Even though there are a few catches which may easily throw off someone under stress:
Handling of bad input (not enough input elements)
Special handling for the head of the input
Swapping variables if you don't know ES6 syntax
Mixing up index and value
So while not hard, there are a couple of caches which can get candidates stuck easily, or cause them to get confused.
var a = [1, 7, 8, 5, 4, 2];
for (var i = 0; i < a.length ; i++) {
var big = 0;
for (var j = 0; j < a.length ; j++) {
if (a[j] > a[i]) big++;
}
if (big == 1) {
return a[i];
}
}
and with predefined methods
a[a.sort().length-2]

Why does 'for x in <array>' not work as expected?

Many programming languages use the syntax of 'for x in ' in order to iterate over a list/array.
It also exists in JavaScript. However, the following code:
var arr = [5, 6, 9, 10];
for (var i in arr) {
console.log(i);
}
outputs the indexes of the array 'arr', and not the elements of the array themselves (unlike other programming languages).
My question is why? Or what is the logic in JavaScript for this behavior?
What you're looking for is for(i of arr). That will iterate the array and give i the value of each element of the array.
Here's the documentation for it
Alternatively, if you want to use for(i in arr) you can call the array element as arr[i], as in that case i is simply the index.
Here is a snippet for all cases.
var arr = [5, 6, 9, 10];
console.log('let i of arr, log i:');
for (let i of arr) {
console.log(i);
}
console.log('let i in arr, log i:');
for (let i in arr) {
console.log(i);
}
console.log('let i in arr, log arr[i]:');
for (let i in arr) {
console.log(arr[i]);
}
My question is why? Or what is the logic in JavaScript for this behavior?
Roughly for the same reason that + means addition instead of subtraction. In other words, for the reason that that is what it is specified to mean.
Javascript has objects with properties and this feature was included (from very early in the history of JS--nearly two decades ago) as a way of iterating over those properties. It so happens that in the case of an array, the indices correspond to properties.

Javascript find the highest value in 2d array based on array itself

I've a multidimensional array
arr = [[[1,1],[2,1],[3,1],[4,2],[5,2],[6,2],[7,3],[8,4]],
[[1,1],[2,1],[3,1],[4,3],[5,3],[6,4],[7,4],[8,5],[9,5],[10,5]]
];
and so on ... but the dimension of the arr is not fixed, is variable.
I've a variable that tell me where to point my attention
var number = 2;
So my goal is the look in any arr[i] and find the max 1st argument based on the 2nd argument, I try to explain better my self, in this particular case if number is 2 my expectation is to have from arr:
for the 1st array in arr -> 6 (because the second argument is 1,1,1,2,2,2,3 so I've to point at the last 2 and return the 1st argument)
for the 2nd array in arr -> 3 (because 2 is missing and the 1 is the last second argument)
I know is a little tricky
My first idea was to make a for loops where I delete all value over my number, then I can take the very last one, but I think I'm over-complicating all.
There is a better and fast way to achieve the same result?
J
You present lists (arrays) of pairs of numbers, where the pairs are sorted in ascending order, first by the second number, then by the first.
What you seem to ask for is: Given a number to search for among the second numbers, e.g. number = 2, find the last pair where the second number is less than or equal to this number, and return the corresponding first number in this pair.
You state that you could use for loops to solve the problem. A straightforward approach could be like the following snippet:
var arr = [[[1,1],[2,1],[3,1],[4,2],[5,2],[6,2],[7,3],[8,4]],
[[1,1],[2,1],[3,1],[4,3],[5,3],[6,4],[7,4],[8,5],[9,5],[10,5]]
];
var findNumber = 2;
var result = [];
for(var i = 0; i < arr.length; i++){
var maxIndex = -1;
for(var j = 0;
j < arr[i].length && arr[i][j][1] <= findNumber;
j++){
maxIndex = j;
}
result.push(arr[i][maxIndex][0]);
}
//gives the expected answers 6 and 3
console.log(result);
Then you ask:
There is a better and fast way to achieve the same result?
A solution involving .map and .reduce could be considered more elegant, like the following:
var arr = [[[1,1],[2,1],[3,1],[4,2],[5,2],[6,2],[7,3],[8,4]],
[[1,1],[2,1],[3,1],[4,3],[5,3],[6,4],[7,4],[8,5],[9,5],[10,5]]
];
var findNumber = 2;
var result = arr.map(function(val){
return val[val.reduce(function(acc, curr, index){
return curr[1] <= findNumber? index : acc;
}, -1)][0];
});
//gives the expected answers 6 and 3
console.log(result);
However, in terms of performance, for loops are likely to perform better (run faster) and are easy to comprehend.
In addition, you mention that
the dimension of the arr is not fixed
You would need to post some code examples on how the dimensionality of your data may vary before it would be possible to provide any answer that handles this aspect.
Update
To handle a single array of pairs, you do not need the outer loop or .map(). Putting the solution above into a reusable function:
function lookupFirstNumberFromSecond(secondNumberToFind, arr){
var j = 0, maxIndex = -1;
while(j < arr.length && arr[j][1] <= secondNumberToFind){
maxIndex = j++;
}
return arr[maxIndex][0];
}
//gives the expected answer 6
console.log(lookupFirstNumberFromSecond(
2,
[[1,1],[2,1],[3,1],[4,2],[5,2],[6,2],[7,3],[8,4]]
));
//gives the expected answer 3
console.log(lookupFirstNumberFromSecond(
2,
[[1,1],[2,1],[3,1],[4,3],[5,3],[6,4],[7,4],[8,5],[9,5],[10,5]]
));
I'm not entirely sure about what you are trying to achieve but I guess Array.reduce is a pretty elegant solution to get a single value out of an array.
e.g.
var number = 2;
[[1,4],[2,1],[3,1],[4,2],[5,2],[6,2],[7,3],[8,4]]
.reduce(function (a, b) {
return ((!a || b[0] > a[0]) && b[1] === number) ? b : a;
});
Not entirely sure what you're trying to solve either, but if you're trying to get the max value in a n dimensional array, then the most straightforward method is to solve this standardly in a recursive manner
function recurseMax(arr) {
if (Number.isInteger(arr)) {
return arr;
}
else {
answer = 0;
for (let i = 0; i < arr.length; i++) {
answer = answer > recurseMax(arr[i]) ? answer : recurseMax(arr[i]);
}
return answer;
}
}
console.log(recurseMax([1,[3, 5], [5, 6, 7, 10], [2, [3, [500]]]])); //Outputs 500
For each element, either is a number or another possible multidimensional element, so we recursively find its max. This avoids potential overhead from a reduce operation (though I'm not experienced enough to speak with confidence whether or not it is completely faster, not really sure of the optimizations V8 can do on reduce or a plain old recursion loop). Either way, the solution is fairly straightforward.
I am answering the question based on the assumption that you mean that the array can have a max dimension of n.

Categories