JavaScript minus zero changes results - javascript

I was playing around with Arrays in jsfiddle and noticed that when I do this:
let a = [0,1,2,3,4];
for (let i in a) {
console.log(a.indexOf(i));
}
it logs:
But when I do:
let a = [0,1,2,3,4];
for (let i in a) {
console.log(a.indexOf(i - 0));
}
it logs:
Minus zero changed the result!
At first I thought it was a jsfiddle problem, but then I tried it with my code editor the same thing happened. Why does this happen can someone explain to me?

When you do:
for (let i in a) ...
This will iterate over indexes of the array as strings. It treats the array like an object and iterates over the indexes like keys. You will get strings: "0", "1"...
You can see that if you print the value and type:
let a = [0,1,2,3,4];
for (let i in a) {
console.log(i, typeof i)
}
Those strings are not in your array — your array has numbers — so findIndex() doesn't find them and gives you -1. However when you subtract 0, javascript converts to an integer for you and suddenly it finds them because the indexes match the values.
What you probably want is for...of to iterate over the values:
let a = [0,1,2,3,4];
for (let i of a) {
console.log("i:", i, typeof i)
console.log("index:", a.indexOf(i));
}

For... in loop is meant to use on objects. In your particular case, the i element in the loop is not a value from the array, but it's key.
Key is typeof string and since you don't have any strings in your array, you are getting -1 with every cycle.
Using - 0 evaluates the string into a number.
Note: It's an unique and "happy" situation, since your elements in the array are sorted, iterated integers starting at 0. That's why it seems to work properly.
Just a quick showcase:
const keys = Object.assign({}, [0, 1, 2, 3]);
console.log(keys);
console.log(typeof Object.keys(keys)[0]);
Snippet above represents how your array is interpreted by for... in loop. As you can easily see, every key from such object is a string.

Please have a look:
let a = [0,1,2,3,4];
for (let i in a) {
console.log(a.indexOf(a[i]));
}

Related

Why is my for loop breaking earlier than expected?

I am trying to solve a problem on leetCode:
Given an unsorted integer array nums, return the smallest missing positive integer.
This is the code I came up with
var firstMissingPositive = function(nums) {
nums.sort();
let x = 1; //this is to compare the elements of nums
for (let num in nums) {
if (nums[num] <= 0) continue; //because anything less than 1 does not matter
else if (nums[num] != x) break; //if x is not present, x is the answer
else x++; // if x is present, x should increment and check for the next integer
}
return x;
};
This code works 106/173 testcases. It does not pass the following case, which looks very simple -
nums = [1,2,3,4,5,6,7,8,9,20];
The output I get is 3, whereas the expected output is 10.
I'm not looking for the right solution to the problem. I'm just curious why this seemingly simple test fails. I do not understand why my loop breaks at 3 when it passes 1 and 2. Please help!
Here's the root cause of your problem (mdn):
The sort() method sorts the elements of an array in place and returns
the sorted array. The default sort order is ascending, built upon
converting the elements into strings, then comparing their sequences
of UTF-16 code units values.
So what you get after sort is [1, 2, 20, 3, ...], as '20' string precedes '3' string. One possible way to fix this it to force sorting by numeric value:
nums.sort((a, b) => a - b);

Is there any way to access the minus index array element like we do for list in python?

var str=['a','c','d','o','p'];
how can I access 'o' in above string using minus index like str[-2]; in javascript;
In python I easily do this but I got stuck here please help out.
I am working this for this task.
A common modern use is the ROT13 cipher, where the values of the letters are shifted by 13 places. Thus 'A' ↔ 'N', 'B' ↔ 'O' and so on.
so I thought of accessing with minus index. For example if the given letter is z the index is 25 so I access str[-str.length+13];
Well there is no way to do this but You can create a function in the javascript for the array and then you can like as follows:
str=["a", "c", "d", "o", "p"];
Array.prototype.accessViaIndex=function(index){
if(index<0){
return this[(this.length+index)]
}
return this[index];
}
console.log(str.accessViaIndex(-1));
i want to access string beyound the length of string that again starts from index 0
JS arrays are not Circular Linked List structure, where if you go beyond bounds, you start with first value.
They are like normal objects where you do not have to specify keys and comes with extensive looping mechanism.
So to achieve this, you will have to use modulus operator (%). Idea is to backtrack the index within the bounds.
var str=['a','c','d','o','p'];
var index = 11;
console.log( str[ index % str.length] );
The .at() method can do exactly what you're after. It can be passed both positive and negative indexes. When a negative index is supplied, it is treated as an offset from the end of the array, so supplying it with -2 is the same as indexing the array manually at array.length-2:
const arr = ['a','c','d','o','p'];
console.log(arr.at(-1)); // same as: arr[arr.length-1], gives p
console.log(arr.at(-2)); // same as: arr[arr.length-2], gives o
console.log(arr.at(1)); // same as: arr[1], gives c
Or, for the time being you can take the length minus the index passed through if the value is negative (as shown in Sourabh Somani answer), here is how a more concise version of that function may look like:
const arr = ['a','c','d','o','p'];
const getElem = (arr, i) => arr[i < 0 ? arr.length+i : i];
console.log(getElem(arr, 3)); // o
console.log(getElem(arr, 0)); // a
console.log(arr); // array is still the same
console.log(getElem(arr, -1)); // p
console.log(getElem(arr, -2)); // o

sorting an array and comparing it to the original

I'm trying to fully understand functional programming when sorting an array why does the original array change to the sorted array also? I
want to check if the array is in ascending order.
let arr = [1,2,8,3,9,88,67];
let newArr = arr.sort((a,b) => a-b);
console.log(newArr);
console.log(arr);
I want to do something like....
if (arr === newArr) {
return true;
} else {
return false;
}
The original arr is also being sorted so it always is true,
some guidance would be great thanks.
That's just the way the sort operator was designed. It modifies the existing array, rather than creating a new array. If you want to create a new array, you can do it like this:
let arr = [1,2,8,3,9,88,67];
let newArr = arr.slice(); // creates a copy of the array
newArr.sort((a,b) => a-b);
console.log(newArr);
console.log(arr);
Javascript array is an object, When 2 variables reference the same object, changing one would change the value of the other
let obj1 = {x:1, y:2};
let obj2 = obj1;
obj2.x = 3;
console.log(obj1);
You can sort it using
let arr = [1,2,8,3,9,88,67];
let newArr = arr.slice().sort((a,b) => a-b);
console.log(newArr);
console.log(arr);
By assigning an object, you take the reference of the object, that means ecery change affects the same object.
For arrays, you could take "a shallow copy" of it with Array#slice and then map the check of the items.
var array = [1, 2, 8, 3, 9, 88, 67],
sorted = array.slice().sort((a, b) => a - b),
position = array.map((a, i) => a === sorted[i]);
console.log(sorted);
console.log(position);
.as-console-wrapper { max-height: 100% !important; top: 0; }
According to your question,
you just need to identify
If the array is in ascending order
To do that just apply some simple logic and we do not want to compare it with a sorted array.
This is the speediest method since it will break the loop on wrong condition.
let arr = [1,2,8,3,9,88,67];
let is_sorted = true;
for(let i=0, length = arr.length; i < length - 1; i++){
if(Number(arr[i]) > Number(arr[i+1])){
is_sorted = false;
break;
}
}
console.log("Is Sorted: ", is_sorted);
This is an XY problem – ie, you want "... to check if the array is in ascending order" and you tried sorting (via Array.prototype.sort) and then you're checking the result using binary operator ==. The result isn't what you expect, so you ask about the sort instead of keeping the focus on your actual goal: checking for ascending order
A case for why you shouldn't sort
Imagine a large array of hundreds or thousands or items. Is the following array in ascending order?
isAscending ([ 5, 1, ... thousands more items ... ])
// => true or false ?
Of course it's false because 1 is less than 5; the array is not in ascending order. Did we have to sort the entire array to arrive at that answer? No, we only needed to look at the first 2 items (in this case) to know the answer is false
Other answers show using .slice to copy the input array – this is silly tho, because of course we don't have to copy an array to determine if it is in ascending order – it's a waste of time/space.
A case for why you shouldn't use ==
Well first, you can't, because of the following (in JavaScript)
[ 1, 2, 3 ] == [ 1, 2, 3 ]
// => false
So how would use == if you could? Maybe an approach would be to check if each element in the first array is equal to each array element in the second array. Ok, now imagine two large arrays of hundreds of thousands of items. Are the following two arrays equal?
[ 1, ... thousands of items ... ] == [ 2, ... thousands of items ... ]
// => true or false ?
We know they're not equal because 1 != 2 – it's the same case as the sorting; there's no sense in comparing the rest of the items because we already know the arrays are not equal
There's other ways to compare Arrays (and objects) in JavaScript, but we only have one input array, so there's no array to compare it to – this is another dead-end to the approach
Check if an array is in ascending order
Ok, so now that were done talking about array sorting and array equality in JavaScript, we can actually write a function that does what you intend it to do
const isAscending = ([x,y,...rest]) =>
x === undefined // array is empty
? true
: y === undefined // single element array
? true
: x > y // first element is larger than second
? false
: isAscending ([y,...rest]) // check remaining elements
console.log (isAscending ([])) // true
console.log (isAscending ([1])) // true
console.log (isAscending ([1,3,5,7])) // true
console.log (isAscending ([5,1,3,7])) // false
Stack-safe recursion
But you have to be careful using recursion in JavaScript – input arrays of just a couple thousand elements could cause a stack overflow in the program above
Using a constant-space looping mechanism, we can rewrite isAscending in a way that works on arrays of any input size. The loop/recur interface gives us an opportunity to track any number/type of state variables, so this implementation also avoids the costly creation of many array slices (in rest parameter and spread argument syntax above)
const recur = (...args) =>
({ type: recur, args })
const loop = f =>
{
let acc = f ()
while (acc.type === recur)
acc = f (...acc.args)
return acc
}
const isAscending = xs =>
xs.length < 2
? true
: loop ((a = 0, b = 1) =>
a === xs.length
? true
: xs [a] > xs [b]
? false
: recur (a + 1, b + 1)) // *
console.log (isAscending ([])) // true
console.log (isAscending ([1])) // true
console.log (isAscending ([1,3,5,7])) // true
console.log (isAscending ([5,1,3,7])) // false
* or recur (b, b + 1), which saves on addition operation per array element
The sort method applied to an array will modify the array itself. So it's logic to have the first array sorted and both arr and newArr will be equal.
To test if the array is in ascending order you may loop through it and check if there is and index i where arr[i+1] < arr[i]
let arr = [1,2,8,3,9,88,67];
let test=true;
for (var i = 1; i < arr.length; i++) {
if(arr[i]<arr[i-1]) {
test=false;
break;
}
}
console.log(test);

Javascript reduce function/ternary operator

function largestInEach(arr) {
var resultArray = [],
highestValue = 0;
for (var i = 0; i < arr.length; i++) {
highestValue = arr[i].reduce(function(a, b){
return a >= b ? a : b;
});
resultArray.push(highestValue);
}
return resultArray;
}
Can someone please explain this code.
The rest of the code is very clear to me, but I have difficulty understanding the reduce function and its application.
I agree with most of the other comments that you should search more and do self learning.
However, I know it is sometimes hard to find the exact info on how things work. So ill explain this to you.
Now coming to your code.
https://jsfiddle.net/Peripona/ppd4L9Lz/
It contains an array of arrays where you at the end create a resulted array with highest or lowest value elements from all the sub arrays.
like you got
var arry = [[1,2,3],[2,3,4],[20,-2,3]]
talking in layman terms...
you got one array if you sort or reduce an array of integers, it might not always generate what you
say for example if you got this data
var ar = [1,3,34,11,0,13,7,17,-2,20,-21]
and if you do normal ar.sort() to get the sorted values
you would expect something like this... as output
" [-21, -2, 0, 1, 3, 7, 11, 13, 17, 20, 34] "
but on the contrary you would get the output like this..
" [-2, -21, 0, 1, 11, 13, 17, 20, 3, 34, 7] "
Now you wonder... why this strange behavior and how does it matter anyhow to my Question..
It Does matter..
Cuz this is what you need to do to get the right output..
The way sort function is written has to work for for String and other types as well. so they convert data into other formats when doing comparison on sort.
So all in all if you pass a function inside and specify that you need the in ascending order that is a-b..
Descending order that is b-a..
ar.sort(function(a,b){return a-b;})
Now coming to another part that is Reduce this function takes a function argument and get you the highest or the lowest value from the array.
therefore if you do..
ar.reduce(function(a,b){return a>=b ? b : a})
will give you -21 as the output..
and if you do
ar.reduce(function(a,b){return a>=b ? a : b})
It will give you : 34
So this function will take multidimensional arrays where each array contains some digits and this function will get you the highest from all those arrays..
I hope this Explains everything.
Reduce function allows you to go through each item in an array, where you will be able to see previous array value, and current array value, in your case:
a = previous value,
b = current value,
-(not in there)-
i = index,
currArray = the array you are working with.
and in your code you are comparing and returning if your previous value is greater than or equal to current value.
a >= b ? a : b;
Conditional (ternary) Operator which is (condition ? do this : or this ) -> Think of it like a if statement
If(a >= b){
return a
}else{
return b
}
see Conditional (ternary) Operator
Also your 'arr' could be multi dimensional array. forexample Trying the following code on http://plnkr.co/edit/?p=preview
hit f12 for developer tools and look at console for results.
var arr = [[1,2],[4,3],[5,23,52]];
var resultArray = [],
var highestValue;
for (var i = 0; i < arr.length; i++) {
highestValue = arr[i].reduce(function(a, b){
return a >= b ? a : b;
});
resultArray.push(highestValue);
}
console.log(resultArray);
You result array contains [2, 4, 52].
I hope this helps.
JS reduce method is applied against two values of array and reduce these two values of array ( a and b) into one (c) based on defined condition (return c = a+b ).
Here in your case the condition was which among two is greater (a>b?a:b).

Sorting an array in javascript

var num_list = [1, 2, 3, 4];
function num_order(a, b) {return b-a; }
num_list.sort(num_order);
I've been through blogs and i have searched on this topic but to no avail. All describe this function to be sorting in descending order but none specify how does that happen..
For example, what values are stored in the parameters a and b and how are these values assigned.. Finally what results the function passes and how does sort method do to those values.. Any help would be appreciated..
Let me specify that there is a post similar to this but the answer in that post is not clear.. One of the user has provided a link here which makes it much clearer
The parameter you pass to the sort method is the comparison function. It will define the order the elements are sorted.
To see what values are being passed to the parameters a and b. Try this in your console:
var num_list = [1, 2, 3, 4];
num_list.sort(function(a, b) {
debugger;
return b-a;
})
MDN has good documentation on the compare function: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort
Have a look at any sort algorithm : at some point they need to compare two elements of the array.
The sort function of most Browsers is heapsort or quicksort, but i will take bubble sort as an example of a sort algorithm :
n = array size
repeat
swapped = false
for i= 0 to n-2
if array [i] > array [i+1] then
swap ( array [i] , array [i+1] )
swapped = true
end for
n = n -1
until swapped = false
we can easily rewrite the comparison to use a comparison function :
n = array size
repeat
swapped = false
for i= 0 to n-2
a = array [i]
b = array [i+1]
if compareFunction(a,b) > 0 then
swap ( array [i] , array [i+1] )
swapped = true
end for
n = n -1
until swapped = false
with :
compareFunction (a,b)
return a-b
So the comparison function is just a function that returns an integer that reflect the items order.
If two elements are the same => the function returns 0, first is bigger => returns >0, second is bigger => returns <0.
Using a comparison function allows to sort any kind of array (i.e. an array containing any kind of item), while still using the very same sort algorithm as the one used for integer sort.

Categories