Array position difference beetween two elements - javascript

I've got this array:
[1,2,3,4,5]
I want to determine the position difference between two elements, but in a "rotation" mode.
Example:
I have 3 and I want to know how far is 2, I do a 3.position - 2.position, and I've got 1.
But, if I have 5, and I want to know the position difference beetween 5.position and 1.position, with the precedent difference, I will have 5-1=4, and because there is array rotation, I want 1.
Do you have an idea of how I can do that ? (I work in Javascript)
EDIT:
Here is a draw that can explain clearer what I want to do
EDIT 2: Better draw

Calculate both the distance within the array, and the distance when wrapping around, and use the smallest.
This code uses pos1 and pos2 as the index of the items in the array arr, and assumes that pos1 < pos2:
var distance = Math.min(pos2 - pos1, pos1 + arr.length - pos2);

Guffa's answer is far more succinct and simple, but I already wrote the JSfiddle so I'll share.
var testArray = [1,2,3,4,5];
function getShortestDistance(element1Name, element2Name){
var result = -1;
var position1 = testArray.indexOf(element1Name);
var position2 = testArray.indexOf(element2Name);
// The distance should never be greater than half of the array length, half being defined as integer division by 2
var maxDistance = Math.floor(testArray.length/2);
if(Math.abs(position1 - position2) >= maxDistance){
result = Math.abs(testArray.length - Math.abs(position1 - position2));
}
else{
result = Math.abs(position1-position2);
}
alert('position1 is ' + position1);
alert('position2 is ' + position2);
alert('Distance is ' + result);
}
getShortestDistance(2,3); // Will return 1
getShortestDistance(1,4); // Will return 2
Here's the JSFiddle in case you want to modify it: http://jsfiddle.net/u71vbeau/16/

Related

Javascript double nested for loop traversing

I am fairly new to JavaScript and I am trying to find a way to write this without using a double for loop by either using higher order function or data structures.
I have these two defined type here
List = {
'start' ? : Position
'end' ? : Position
}
Position = {
row?: number;
column?: number;
}
This is the for loop that I believe can be optimized or avoid using for loop for.
for (let row = list.start.row; row <= list.end.row; row++) {
for (let col = list.start.column; col <= list.end.column; col++) {
console.log(`row: ${row}, col: ${col}`);
}
}
So if the I have the list defined as
list.start.row = 2, list.start.column = 4
list.end.row = 3, list.start.column = 6
I should have (2,4) (2,5) (2,6) (3,4) (3,5) (3,6) output as the console messages and order does not matter. What would be the most optimal way of doing this? Thank you in advance!
You can absolutely do this with a single loop. In fact its a very common way to navigate multi dimensional arrays in memory. For example, you have a chunk of raw image data, and you want to get the pixel information at point(80,120). You'd have to be able to convert the (x,y) coordinates to some offset. This is trivial if you know the width of a row. To get the pixel information, assuming each pixel is 8 bits simply calculate i = y * width + x. You can use this same technique to create a multi dimensional array using one loop. You'd have to apply the above formula in reverse to find the (x,y) points from (i, width). Computing the width is easy, its the end.column - start.column and calculating the number of elements would be the height * width. The height is obviously the difference in rows. You would then loop through your entire linear domain and project the i back to (x,y) in your array.
It might be easier to just look at the sample code.
const list = {
start: { row: 2, column: 4 },
end: { row: 3, column: 6 }
};
const x0 = list.start.column;
const y0 = list.start.row;
const x1 = list.end.column;
const y1 = list.end.row;
const width = x1 - x0 + 1; // range is inclusive so [2,2] has a width of 1.
const height = y1 - y0 + 1; // same here.
const results = Array.from({ length: width * height }, (_, n) => {
const row = (n - n % width) / width + y0;
const column = n % width + x0;
return [row, column];
});
console.log(results);
Should you do it instead of a nested loop? Probably not in javascript. Complexity is still O(mn) and so its no faster algorithmically then a nested loop. The compiler/vm will likely optimize a [x,y] nested loop into something like this for you anyway.
It always will be a nested loop if you want to print all values of x for all values of y. You can use different syntax, such as forEach, but it'll always be the same concept - and the solution you have is actually the most optimal and efficient (as there'll always be xy combinations for x and y values; so if your time complexity is O(mn), it's fine).

reverseArrayInPlace() not working properly

There have been other questions about this problem, but I'd like to know why my code does not reverse the array given. Note: I am very new to coding, just teaching myself and trying to get practice for personal interest.
In the book Eloquent Javascript, we are asked to write two different functions which reverse an array. The first function, reverseArray, is supposed to output a new array which is the reverse of the given one. That one is easy enough.
The second function, reverseArrayInPlace, is supposed to change the given array so it is reversed. It is assumed that merely using the first function and then assigning its value to the first array is "cheating". Also, we cannot use the .reverse method.
Here is my attempt, and I can't figure out why it doesn't work:
var reverseArrayInPlace = function(anArray) {
for (var i = 1; i < anArray.length; i++) {
anArray = anArray.slice(i, i+1).concat
(anArray.slice(0,i)).concat(anArray.slice(i+1));
}
}
Note: I don't like how I wrote this function, but nonetheless I can't decide why it doesn't work.
Here is the test code given in the book and the target output:
var arrayValue = [1, 2, 3, 4, 5];
reverseArrayInPlace(arrayValue);
console.log(arrayValue);
// → [5, 4, 3, 2, 1]
The hint given in the book says:
"The trick is to swap the first and last elements, then the second and second-to-last, and so on. You can do this by looping over half the length of the array (use Math.floor to round down—you don’t need to touch the middle element in an array with an odd length) and swapping the element at position i with the one at position array.length - 1 - i. You can use a local variable to briefly hold on to one of the elements, overwrite that one with its mirror image, and then put the value from the local variable in the place where the mirror image used to be."
I don't like my idea, but I like this hint even less. Is there something more in the spirit of changing the array "in place" with the hint's idea than mine?
Thanks for the help. And again, we can't just use something called .reverse on the given array.
Although this is not the shortest solution, I've tried to write it to be easy to understand.
Basically we create 2 index pointers into the array, left and right, with left of course starting at the first element, and then right the last one.
Because we don't need to swap the middle a simple check of left < right inside a while loop will make it stop before it gets there.
We then use the tmp var, to use as a temporary placeholder while we swap the items, after which we can increase the left and decrease the right index pointers.
To make this an in-place replace, we use index array access methods, using [] instead of slice etc.
var reverseArrayInPlace = function(anArray) {
var left = 0, right = anArray.length - 1, tmp;
while (left < right) {
tmp = anArray[left];
anArray[left] = anArray[right];
anArray[right] = tmp;
left ++;
right --;
}
}
var a = [1,2,3,4,5];
reverseArrayInPlace(a);
console.log(a);
I see two errors:
First is that you have doubled concat call:
var reverseArrayInPlace = function(anArray) {
for (var i = 1; i < anArray.length; i++) {
anArray = anArray.slice(i, i+1).concat // two concats! one here and one on next line
concat(anArray.slice(0,i)).concat
(anArray.slice(i+1));
}
}
The other error is that you don't return anything. The corrected function looks like:
var reverseArrayInPlace = function(anArray) {
for (var i = 1; i < anArray.length; i++)
anArray =
anArray
.slice(i, i + 1)
.concat(anArray.slice(0, i))
.concat(anArray.slice(i + 1));
return anArray;
};
Note however that this is not even close to being an "in place" reversal. This code will make a lot of intermediate arrays before getting to the final result. A real in place reversal would be much different, probably swapping elements around.
Depending on requirements, one possibility could be to swap elements from the end with elements from the beginning, stopping in the middle. A swap will often consist of using a temp variable, which can be considered a violation of "in-place" as well.
To do it completely in place, even without a temp variable, it's possible to use an XOR trick to swap elements. This will only work with numbers, though, not things like objects. You also don't want to swap the central element (if there is one) this way, since you would zero it out.
// tricky way to swap two elements (assumes front != back)
anArray[front] ^= anArray[back];
anArray[back] ^= anArray[front];
anArray[front] ^= anArray[back];
Your code is working when you walk until the end of the array (array.length + 1) and when you return the new array.
var numbers = [1, 2, 3, 4, 5, 6];
var reverseArrayInPlace = function(arr) {
for (var i = 1; i < arr.length + 1; i++) {
arr = arr.slice(i, i + 1).concat(arr.slice(0, i)).concat(arr.slice(i + 1));
}
return arr;
}
var r = reverseArrayInPlace(numbers);
console.log(r);
But the question is about reversing the used array with other criteria.
The hint in the book gives you almost the solution.
It's about
swap
half the length of the array
array.length - 1 - i
A swap is
var n = [4, 9];
var temp = n[0]; // Assign left to a temporary (locale) variable for a "briefly hold"
n[0] = n[1]; // Assign right to left
n[1] = temp; // Assign the temporary variable (left) to right
console.log(n);
Half the length of the array
var half = Math.floor(arr.length / 2);
with Math.floor. It is there to catch also an an array with odd length
Math.floor(7 / 2) -> 3
In total
var numbers = [1, 2, 3, 4, 5];
function reverseArrayInPlace(arr) {
var half = Math.floor(arr.length / 2);
for (var i = 0; i < half; i += 1) {
// Swap start
var temp = arr[i];
arr[i] = arr[arr.length - 1 - i];
arr[arr.length - 1 - i] = temp;
// Swap end
}
}
reverseArrayInPlace(numbers);
console.log(numbers);

Applying Fibonacci, working with large numbers

I am trying to successfully complete this challenge on the Rosalind page. The challenge is:
Given: Positive integers n≤40 and k≤5.
Return: The total number of rabbit pairs that will be present after n months if we begin with 1 pair and in each generation, every pair of reproduction-age rabbits produces a litter of k rabbit pairs (instead of only 1 pair).
The exercise gives a text file of two numbers, the n and k mentioned above.
My code, which attempts to implement Fibonacci, works as expected for lower numbers of months. However, the result begins to become extremely large for higher numbers of months, and in each case I am given, my answer is Infinity.
Is my formula applied incorrectly? Or is Javascript a bad choice of language to use for such an exercise?
My code:
function fibonacciRabbits(months, pairs){
var months = months;
var numberOfPairs = pairs;
var result = 0;
// Declare parent & child arrays with constants
var parentArr = [1, numberOfPairs + 1]
var childArr = [numberOfPairs, numberOfPairs]
var total = []
// Loop from the point after constants set above
for(var i = 2; i < months - 2 ; i++){
parentArr.push(parentArr[i-1] + childArr[i-1])
childArr.push(parentArr[i-1] * childArr[i-2])
total.push(parentArr[i-1] + childArr[i-1])
}
result = childArr[childArr.length - 1] + parentArr[parentArr.length - 1]
console.log(months + ' months and ' + numberOfPairs + ' pairs:\n')
console.log('parentArr:\n', parentArr)
console.log('childArr:\n', childArr)
console.log('total\n', total)
console.log('result:', result)
console.log('\n\n\n')
}
fibonacciRabbits(5, 3)
fibonacciRabbits(11, 3)
fibonacciRabbits(21, 3)
fibonacciRabbits(31, 2)
And here is a REPL
Here is a more brief solution that doesn't produce such large numbers, and handles the maximum case without hitting infinity in Javascript. I think your solution was getting too big too fast.
function fibonacciRabbits(months, reproAmount){
var existingAdults = 0;
var adultPairs = 0;
var childPairs = 1;
for(var i = 2; i <= months; i++){
adultPairs = childPairs; //children mature
childPairs = (existingAdults * reproAmount); //last month's adults reproduce
existingAdults += adultPairs; //new adults added to the reproduction pool
}
console.log(existingAdults + childPairs);
}
To make sure you are on the right track, test your function with:
fibonacciRabbits(1, 1);
fibonacciRabbits(2, 1);
Which from the website says: f(1)=f(2)=1. So these should both produce "1" no matter what. Your code produces "3" for both of these.

Why does it only sums the last two numbers?

I am trying to make a program that sums every number given as parameter. To do so, I wrote the following code:
var x = 0;
var i = 2;
while (isNaN(+process.argv[i + 1]) == false){
x = +process.argv[i] + +process.argv[i + 1];
i++;
}
console.log(x);
The problem is that the code I wrote sums only the 2 last parameter.
I launch my code using node sumArgs.js 1 2 3
and it returns 5.
What is the problem with my code and why isn't it working as planned ?
What is happening every time you loop through, it is taking the current parameter, and the next, and setting x to equal the sum of those.
x needs to be added to, not set. You can do this either:
x += process.argv[i]
or
x = x + process.argv[i]
I'm also not sure why you are adding 2 arguments each loop, as this will cause the sum to be incorrect at the end (unless you increment i twice each loop).
I should note that map reducing it, as in another comment, wouldn't work as the first 2 arguments would not be parameters passed to the program, they would be "node" and "program.js".
var x = 0;
var i = 2;
while (isNaN(+process.argv[i]) == false){
x = x + process.argv[i];
i++;
}
console.log(x);
However, what you could do is use slice:
var sum = process.argv.slice(2).reduce(function(previousValue, currentValue) {
return previousValue + currentValue;
});

Javascript, finding first significant figure (values ranging from 87.352 to 0.0002432)

I have created a GPS system using coordinates.
I have found the highest and lowest longitude and latitude coordinates using this function:
var maxLng = 0;
var maxLat = 0;
var minLng = 180;
var minLat = 180;
for(var i=0; i<coordinates.length; i++)
{
//get max coordinates (the +90 is to remove negative numbers)
if (coordinates[i][0]+90 > maxLat)
{
maxLat = coordinates[i][0] + 90;
}
if (coordinates[i][1]+90 > maxLng)
{
maxLng = coordinates[i][1]+ 90;
}
//get min coordinates
if (coordinates[i][0]+90 < minLat)
{
minLat = coordinates[i][0] + 90;
}
if (coordinates[i][1]+90 < minLng)
{
minLng = coordinates[i][1] + 90;
}
}
console.log(maxLat, maxLng,minLat, minLng);
//calculate distance between max and min points
var lngDistance = maxLng - minLng;
var latDistance = maxLat - minLat;
console.log(lngDistance, latDistance);
This outputs the distance between the 2 furthest apart longitude and latitude points, which I then plan to use to create a basic 2d map looking like this:
I need to convert the points, they can be a range of value such as:
0.0009321
19.332
1.9432123
0.0013432423
0.23432423
0.000034324
I want to basically convert all the numbers to 2 significant figures in front of the decimal point and store the result in the array stating how many shifts I have used.
I would want the output to be something like this (original number, converted number, shifts used):
[0.0009321, 93.21, 4]
[19.332, 19.332, 0]
[1.9432123, 19.432123, 1]
[0.0013432423, 13.432423, 3]
...
I am thinking find the first significant figure then count how far away from the decimal point this is. I found a few posts about using REGEX to do this, but I have never used REGEX before.
Can anybody give me some pointers?
Cheers.
That was a fun one figuring out.
Made a basic function for you, and as far as I can see it works.
function change(data){
var ret=new Array();
for(var i=0,len=data.length;i<len;i++){
// make string from number, remove the dot
var st=(''+data[i]).replace('.','');
//remove leading zero's from string
var no_zero=st.replace(/^0+/,'');
//make value
var val=parseInt(no_zero)/(Math.pow(10,no_zero.length-2));
//calculate amount of steps
var steps=Math.round(Math.log(Math.round(val/data[i]))/Math.log(10));
//correction for floating point
if(data[i]<0.01)steps--;
ret.push([data[i],val,steps]);
}
return ret;
}
And a working Fiddle

Categories

Resources