reverseArrayInPlace() not working properly - javascript

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

Related

Returning Null - why is this going wrong?

I am returning null with this code, however I cannot see why/where this is going wrong. (It may be due to the sort function since I got this from a well upvoted snippet on how to sort an array). I care more about the understanding than the correct answer.
Task I am trying to achieve :
Ratiorg got statues of different sizes as a present from CodeMaster for his birthday, each statue having an non-negative integer size. Since he likes to make things perfect, he wants to arrange them from smallest to largest so that each statue will be bigger than the previous one exactly by 1. He may need some additional statues to be able to accomplish that. Help him figure out the minimum number of additional statues needed.
Example
For statues = [6, 2, 3, 8], the output should be
solution(statues) = 3.
Ratiorg needs statues of sizes 4, 5 and 7.
My code & thinking:
function solution(statues) {
let total = 0;
statues.sort(function(a, b) { //From what I understand this should sort the array numerically
return a - b;
});
for (let i = 1; i < statues.length; i++) { //iterate through the array comparing the index to the one before it
if (statues[i + 1] != (statues[i] + 1)) { //if there is a diff between index of more than 1 it will add the diff
total += statues[i + 1] - statues[i]; //to the total variable
}
}
return total;
}
const result = solution([6, 2, 3, 8]);
console.log(result);
Thanks to people who commented who helped me see that there were some errors in my logic - I have now changed the if statement to compare an index starting at 1 to the behind it i.e index 1 compared to index 0. On top of that, there was an issue with the following line total += statues[i] - statues[i-1];
I replaced that with a for loop so that it counts up to the number rather than a simple subtraction of it.
function solution(statues) {
//[6, 2, 3, 8] --- 2,3,6,8 --- 3,6 7-2,
let total = 0;
statues.sort(function(a, b) {
return a - b;
});
for(let i =1; i<statues.length; i++){
if(statues[i] != (statues[i-1]+1) ){
//total += statues[i] - statues[i-1];
for(let j = statues[i-1]; j<statues[i]-1; j++){
total += 1;
}
}
}
return total;
}

LeetCode 120: Triangle - Minimum path sum

I'm doing this problem on leetcode:
Given a triangle, find the minimum path sum from top to bottom. Each step you may move to adjacent numbers on the row below.
My logic is to find the minimum number in each array and add that to the sum.
This is my code in javascript:
var minimumTotal = function(triangle) {
let sum = 0;
for (let i = 0; i < triangle.length; i++) {
sum += Math.min.apply(null, triangle[i])
}
return sum;
};
But it doesn't work for this test case: [[-1],[2,3],[1,-1,-3]].
The expected output is -1. I'm confused how it should equal -1, because -1 + 2 = 1 and none of the numbers in third array equal -1 when summed with 1.
I looked at the discussion answers and they all used some sort of dynamic programming solution.
What am I doing wrong?
There is a path where the output should be -1.
[
[ -1 ],
[ 2, 3 ],
[ 1, -1, -3 ],
]
-1 + 3 - 3 = -1
The problem is that you only have 2 possible branches at each fork, whereas it appears you're taking the lowest number from the entire row.
Under the rules of the challenge, you shouldn't be able to go from 2 in the second row to -3 in the third row, which would be the most efficient path under your approach.
What you are doing does not seem to follow the desired data structure of the problem. You are generating an int, while the desired output should be an array.
The correct answers are already posted in the discussion board:
This solution is an accepted one (just tested it):
JavaScript
var minimumTotal = function(triangle) {
for (let row = triangle.length - 2; row > -1; row--)
for (let col = 0; col < triangle[row].length; col++)
triangle[row][col] += Math.min(triangle[-~row][col], triangle[-~row][-~col])
return triangle[0][0]
}
-~row is the same as row + 1 (bitwise version).
Reference
Explains it here
If you might be interested in Python and Java, these are "accepted" solutions:
Python
class Solution:
def minimumTotal(self, triangle):
if not triangle:
return
dp = triangle[-1]
for row in range(len(triangle) - 2, -1, -1):
for col in range(len(triangle[row])):
dp[col] = min(dp[col], dp[-~col]) + triangle[row][col]
return dp[0]
Java
class Solution {
public int minimumTotal(List<List<Integer>> triangle) {
int[] dp = new int[-~triangle.size()];
for (int row = triangle.size() - 1; row > -1; row--)
for (int col = 0; col < triangle.get(row).size(); col++)
dp[col] = Math.min(dp[col], dp[-~col]) + triangle.get(row).get(col);
return dp[0];
}
}
For each step, you may move to an adjacent number of the row below. More formally, if you are on index i on the current row, you may move to either index i or index i + 1 on the next row.
The above statement is part of the question and it helps to create a graph like this.
Dynamic programming is used where we have problems, which can be divided into similar sub-problems, so that their results can be re-used. We start from the bottom and determine which minimum value we take and then we are going to be using that minimum value above. That is why we use dynamic programming here. Now each row gets 1 size bigger, so you can imagine under the last row, we have 4 0's.
that is why in dynamic programming we always create an array whose size is always 1 greater than the original array. We fill the array with default values. I will be explaining in python but later on I will challenge myself to write in javascript. first, initialize the dp array
dp=[0]*(len(triangle)+1) #[[0],[0],[0],[0]]
Now, we are starting from the level=[1,-1,3]. For this level, since the bottom is full of 0's, our dp array will be
dp=[1,-1,-3,0]
now we are moving above level, level=[2,3], but we are using the data from the bottom. (That is why we are using dynamic programming). From 2, its index is 0, so I ask myself what is the minimum between 0'th and 1'st value of the dp array. Whichever is minimum we add it to 2? Obviously, -1 is minimum, 2+(-1)=1 and dp gets updated.
dp=[1, -1, -3, 0]
We do the same for 3. its index is 1, and we ask what is the min(-1,3), because 3 is pointing to -1 and 3 and then we add -1 to 3 which is 2. new dp
dp=[1,0,-3,0]
Now we are at the root level. -1 and its index is 0. We ask what is min value of index 0'th and index 1'st of the dp array. min(1,0)=0 and we add it to -1. dp gets updated
dp=[-1,0,3,0]
and finally, we return dp[0]=0
Here is the code in python:
from typing import List
class Solution:
def min_total(self,triangle:List[List[int]])->int:
# dp[] is the bottom row
dp=[0]*(len(triangle)+1)
// triangle[::-1] says start from the last element of triangle
for row in triangle[::-1]:
for i,n in enumerate(row):
dp[i]=n+min(dp[i],dp[i+1])
return dp[0]
Here is javascript code:
function minPath(triangle) {
let dp = new Array(triangle.length + 1).fill(0);
for (let row = triangle.length - 1; row >= 0; row--) {
for (let i = 0; i <= triangle[row].length - 1; i++) {
dp[i] = triangle[row][i] + Math.min(dp[i], dp[i + 1]);
}
}
console.log(dp);
return dp[0];
}
const triangle = [[-1], [2, 3], [1, -1, -3]];
console.log(minPath(triangle));
As this was brought back up, it's worth pointing out that the dynamic programming technique discussed in answers and comments can be done very simply with a reduceRight:
const minSum = (triangle) =>
triangle .reduceRight ((ms, ns) => ns .map (
(n, i) => n + (i > ms.length ? ms[i] : Math .min (ms [i], ms [i + 1]))
)) [0]
console .log (minSum ([[-1], [2, 3], [1, -1, -3]])) //=> -1
console .log (minSum ([[2], [3, 4], [6, 5, 7], [4, 1, 8, 3]])) //=> 11
console .log (minSum ([[-10]])) //=> -10
At each step we calculate the minimum paths through all the elements in a row. ms is the minimum paths through the row below (and on the initial pass will just be the bottom row) and for each n in our row ns, if we're at the rightmost element, we just copy the value from the corresponding row below, otherwise we take the minimum of the element right below and the one to its right.
Since this is called a triangle, I think we can assume that the first row has only one element. But if that's not the case, we could simply take the minimum of the results rather than taking the first element in the final value. That is, we could replace triangle .reduceRight ( ... ) [0] with Math .min (... triangle .reduceRight ( ... )).
/*
[120] Triangle
https://leetcode.com/problems/triangle/description/
*/
import java.util.List;
class Solution {
public int minimumTotal(List<List<Integer>> triangle) {
if (triangle.size() == 0)
return 0;
int rows = triangle.size();
int cols = triangle.get(rows - 1).size();
int[] tmp = new int[cols];
int index = 0;
for (int var : triangle.get(rows - 1)) {
tmp[index++] = var;
}
for (int i = rows - 2; i >= 0; i--) {
for (int j = 0; j <= triangle.get(i).size() - 1; j++) {
tmp[j] = triangle.get(i).get(j) + Math.min(tmp[j], tmp[j + 1]);
}
}
return tmp[0];
}
}

JavaScript: Subtracting ranges of numbers

I'm trying to write a JS function which has two parameters, include and exclude, each an array of objects {X, Y} which represents a range of numbers from X to Y, both included.
The output is the subtraction of all the ranges in include with all the ranges in exclude.
For example:
include = [ {1,7}, {9,10}, {12,14} ]
exclude = [ {4,5}, {11,20} ]
output = [ {1,3}, {6,7}, {9,10} ]
{4,5} broke {1,7} into two range objects: {1,3} and {6,7}
{9,10} was not affected
{12,14} was removed entirely
You can use sweep line algorithm. For every number save what it represents (start and end, inclusion and exclusion ). Then put all the number in an array and sort it. Then iteratively remove elements from the array and perform the appropriate operation.
include_list = [[1,7]]
exclude_list = [[4,5]]
(1,start,inclusion),(4,start,exclusion),(5,end,exclusion),(7,end,inclusion)
include = 0
exclude = 0
cur_element = (1,start,inclusion) -> include = 1, has_open_range = 1, range_start = 1 // we start a new range starting at 1
cur_element = (4,start,exclusion) -> exclude = 1, has_open_range = 0, result.append ( [1,4] ) // we close the open range and add range to result
cur_element = (5,end,exclusion) -> exclude = 0, has_open_range = 1, range_start = 5 // because include was 1 and exclude become 0 we must create a new range starting at 5
cur_element = (7,end,inclusion) -> include = 0, has_open_range = 0, result.append([5,7]) // include became zero so we must close the current open range so we add [5,7] to result
maintain variables include and exclude increment them with start of the respective elements and decrement them upon receiving end elements. According to the value of include and exclude you can determine wether you should start a new range, close the open range, or do nothing at all.
This algorithm runs in linear time O(n).
The rule for integer set arithmetic for subtraction of two sets X,Y is
X − Y := {x − y | x ∈ X, y ∈ Y }
but that's not what you want, as it seems.
You can assume ordered sets in your example which allows you to set every occurrence of x==y as an arbitrary value in a JavaScript array and use that to split there. But you don't need that.
The set difference {1...7}\{4...5} gets expanded to {1,2,3,4,5,6,7}\{4,5}. As you can easily see, a subtraction with the rule of set arithmetic would leave {1,2,3,0,0,6,7} and with normal set subtraction (symbol \) you get {1,2,3,6,7}.
The set difference {12...14}\{11...20} gets expanded to {12,13,14}\{11,12,13,14,15,16,17,18,19,20}; the set arithm. difference is {-11,0,0,0,-15,-16,...,-20} but the normal set-subtraction leaves the empty set {}.
Handling operations with the empty set is equivalent to normal arithmetic {x}-{}={x} and {}-{x} = {-x} for arithmetic set rules and {x}\{}={x},{}\{x}= {} with normal rules
So what you have to use here, according to your example, are the normal set rules. There is no need to expand the sets, they can be assumed to be dense.
You can use relative differences(you may call them distances).
With {1...7}\{4...5} the first start is small then the second start and the first end is greater the the second end, which resulted in two different sets.
With {12...14}\{11...20} the first start is greater than the second start and the first end is lower then the second end which resulted in an empty set.
The third example makes use of the empty-set rule.
Do you need an example snippet?
Here's an answer that works with fractions and that isnt just brute forcing. I've added comments to explain how it works. It may seem big the the premise is simple:
create a method p1_excluding_p2 that accepts points p1 and p2 and returns of an array of points that exist after doing p1 - p2
create a method points_excluding_p2 which performs the EXACT same operation as above, but this time allow us to pass an array of points, and return an array of points that exist after subtracting p2 from all the points in our array, so now we have (points) - p2
create a method p1_excluding_all which takes the opposite input as above. This time, accept one point p1 and many exclusion points, and return the array of points remaining after subtracting all the exclusion points. This is actually very easy to create now. We simply start off with [p1] and the first exclusion point (exclusion1) and feed this into points_excluding_p2. We take the array that comes back (which will be p1 - exclusion1) and feed this into points_excluding_p2 only this time with exclusion2. We continue this process until we've excluded every exclusion point, and we're left with an array of p1 - (all exclusion points)
now that we have the power to perform p1 - (all exclusion points), its just a matter of looping over all our points and calling p1_excluding_all, and we're left with an array of every point subtract every exclusion point. We run our results through remove_duplicates incase we have any duplicate entries, and that's about it.
The code:
var include = [ [1,7], [9,10], [12,14] ]
var exclude = [ [4,5], [11,20] ]
/* This method is just a small helper method that takes an array
* and returns a new array with duplicates removed
*/
function remove_duplicates(arr) {
var lookup = {};
var results = [];
for(var i = 0; i < arr.length; i++) {
var el = arr[i];
var key = el.toString();
if(lookup[key]) continue;
lookup[key] = 1;
results.push(el);
}
return results;
}
/* This method takes 2 points p1 and p2 and returns an array of
* points with the range of p2 removed, i.e. p1 = [1,7]
* p2 = [4,5] returned = [[1,3],[6,7]]
*/
function p1_excluding_p2(p1, p2) {
if(p1[1] < p2[0]) return [p1]; // line p1 finishes before the exclusion line p2
if(p1[0] > p2[1]) return [p1]; // line p1 starts after exclusion line p1
var lines = [];
// calculate p1 before p2 starts
var line1 = [ p1[0], Math.min(p1[1], p2[0]-1) ];
if(line1[0] < line1[1]) lines.push(line1);
// calculate p1 after p2 ends
var line2 = [ p2[1]+1, p1[1] ];
if(line2[0] < line2[1]) lines.push(line2);
// these contain the lines we calculated above
return lines;
}
/* this performs the exact same operation as above, only it allows you to pass
* multiple points (but still just 1 exclusion point) and returns results
* in an identical format as above, i.e. points = [[1,7],[0,1]]
* p2 = [4,5] returned = [[0,1],[1,3],[6,7]]
*/
function points_excluding_p2(points, p2) {
var results = [];
for(var i = 0; i < points.length; i++) {
var lines = p1_excluding_p2(points[i], p2);
results.push.apply(results, lines); // append the array lines to the array results
}
return results;
}
/* this method performs the same operation only this time it takes one point
* and multiple exclusion points and returns an array of the results.
* this is the important method of: given 1 point and many
* exclusion points, return the remaining new ranges
*/
function p1_excluding_all(p1, excluded_pts) {
var checking = [p1];
var points_leftover = [];
for(var i = 0; i < exclude.length; i++) {
checking = points_excluding_p2(checking, exclude[i]);
}
return remove_duplicates(checking);
}
/* now that we have a method that we can feed a point and an array of exclusion
* points, its just a simple matter of throwing all our points into this
* method, then at the end remove duplicate results for good measure
*/
var results = [];
for(var i = 0; i < include.length; i++) {
var lines = p1_excluding_all(include[i], exclude);
results.push.apply(results, lines); // append the array lines to the array results
}
results = remove_duplicates(results);
console.log(results);
which returns:
[[1,3],[6,7],[9,10]]
NOTE: include = [ {1,7}, {9,10}, {12,14} ] is not valid javascript, so I assumed you as passing in arrays of arrays instead such as:
include = [ [1,7], [9,10], [12,14] ]
Brute force method (a solution, may not be the most eloquent):
function solve_range(include, exclude) {
numbers = [];
include.forEach(function (range) {
for (i = range[0]; i <= range[1]; i++) {
numbers[i] = true;
}
});
exclude.forEach(function (range) {
for (i = range[0]; i <= range[1]; i++) {
numbers[i] = false;
}
});
contiguous_start = null;
results = [];
for (i = 0; i < numbers.length; i++) {
if (numbers[i] === true) {
if (contiguous_start == null) {
contiguous_start = i;
}
} else {
if (contiguous_start !== null) {
results[results.length] = [contiguous_start, i - 1];
}
contiguous_start = null;
}
}
return results;
}
var include = [
[1, 7],
[9, 10],
[12, 14]
];
var exclude = [
[4, 5],
[11, 20]
];
var output = solve_range(include, exclude);
https://jsfiddle.net/dwyk631d/2/
Here's a working solution that handles the 4 possible overlap scenarios for an exclusion range.
var include = [{from:1, to: 7},{from: 9, to: 10},{from: 12, to: 14}];
var exclude = [{from:4, to: 5}, {from: 11, to: 20}];
//result: {1,3}, {6,7}, {9,10}
var resultList = [];
for (var i=0;i<include.length;i++){
var inc = include[i];
var overlap = false;
for (var x=0;x<exclude.length;x++ ){
var exc = exclude[x];
//4 scenarios to handle
if (exc.from >= inc.from && exc.to <= inc.to){
//include swallows exclude - break in two
resultList.push({from: inc.from, to: exc.from - 1});
resultList.push({from: exc.to + 1, to: inc.to});
overlap = true;
}else if (exc.from <= inc.from && exc.to >= inc.to){
//exclude swallows include - exclude entire range
overlap = true;
break;
}else if (exc.from <= inc.from && exc.to <= inc.to && exc.to >= inc.from){
//exclusion overlaps on left
resultList.push({from: exc.to, to: inc.to});
overlap = true;
}else if (exc.from >= inc.from && exc.to >= inc.to && exc.from <= inc.to){
//exclusion overlaps on right
resultList.push({from: inc.from, to: exc.from - 1});
overlap = true;
}
}
if (!overlap){
//no exclusion ranges touch the inclusion range
resultList.push(inc);
}
}
console.log(resultList);
Perhaps we can make it slightly more efficient by merging labeled intervals into one sorted list:
include = [ {1,7}, {9,10}, {12,14} ]
exclude = [ {4,5}, {11,20} ]
merged = [ [1,7,0], [4,5,1], [9,10,0], [11,20,1], [12,14,0] ];
Then, traverse the list and for any excluded interval, update any surrounding affected intervals.
try this
function excludeRange(data, exclude) {
data = [...data] // i don't want inplace edit
exclude.forEach(e=>{
data.forEach((d,di)=>{
// check intersect
if (d[0] <= e[1] && e[0] <= d[1]) {
// split into two range: [Ax, Bx-1] and [By+1, Ay]
var ranges = [
[d[0], e[0]-1],
[e[1]+1, d[1]],
]
// keep only valid range where x <= y
ranges = ranges.filter(e=>e[0]<=e[1])
// replace existing range with new ranges
data.splice(di, 1, ...ranges)
}
})
})
return data
}
I try to implement this short and simple as possible
edit: add explain and update more readable code
the algorithm with A-B
if intersect -> we split into two range: [Ax, Bx-1] and [By+1, Ay]
then we filter out invalid range (where x > y)
else: keep A

Array position difference beetween two elements

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/

Trouble sorting an array of numbers into evens and odds

I'm just learning JavaScript and am working on a problem where I sort an array of numbers into odd and even arrays.
To test whether I am successful, I am "alerting" the arrays at the end (and expect to see the even numbers in the first alert, the odd numbers in the second alet). However, everything I try hasn't worked; I just get an alert with 1, then an empty alert.
Can anyone tell me why this is not working?
var numbs = [1, 2, 34, 54, 55, 34, 32, 11, 19, 17, 54, 66, 13];
Sort(numbs);
function Sort(nums) {
var evens = [];
var odds = [];
for (var i = 0; i < arguments.length; i++) {
if (nums[i] % 2) {
evens.push(nums[i]);
} else {
odds.push(nums[i]);
}
}
alert(evens.toString());
alert(odds.toString());
}
for (var i = 0; i < arguments.length; i++) {
^^^^^^^^^^^^^^^^
This is your problem. arguments refers to the array of all arguments passed to the function (ex. the arguments value for function(a, b, c) is [a, b, c]). Therefore, in your case, arguments.length will be 1 since there is only one argument.
In fact, as you may have gathered, the use of arguments is often unnecessary. Typically you can just check if the arguments are undefined if you want to know whether they have been provided or not, and the use of arguments will slow down your code drastically. You should probably almost never have to use arguments in your code at all.
Simply replace that line with:
for (var i = 0; i < nums.length; i++) {
A few other observations:
Your if condition is flipped—it detects whether a number is odd, not even. Either flip the bodies of the if and else statements or use something like nums[i] % 2 !== 1 instead.
You use numbs as a local variable before the function call, and then call it nums in the function. Why? This seems odd and confusing, and standardizing on a single name will help reduce mistakes in the future. (You could also call them, say, userAges outside the function and nums inside if you're passing something specific to it.)
Your function is called Sort with a capital S. This is unusual because the standard naming conventions for JavaScript dictate that variables and functions be camelCased, i.e. starting with a lowercase letter and having uppercase letters to distinguish new words.
The indentation seems to be quite erratic. This makes your code harder to read. Try using an IDE or some sort of text editor that will automatically indent your code for you, making it much simpler to read.
The answer from #Doorknob 冰 captures very well the essence of what went wrong, and describes how you can go about fixing it.
But if you're interested in a slightly more advanced technique, then this code will work, and it is, to my mind much more elegant:
var isEven = function(n) {return n % 2 === 0;};
var isOdd = function(n) {return n % 2 !== 0;};
numbs.filter(isEven); //=> [2, 34, 54, 34, 32, 54, 66]
numbs.filter(isOdd); //=> [1, 55, 11, 19, 17, 13]
In other words, the work you're doing to filter the items is already a built-in method on the array prototype. You just need to define predicate functions to use with it, such as isEven and isOdd.
(Note that the test in isOdd is not n % 2 === 1 since the % operator is slightly different from the mathematical modulus operation, and will return a negative value if the dividend is negative.)
You need to make a couple fixes (and should clean up your code's formatting a bit for readability & maintainability – like I have done below):
var numbs = [1,2,34,54,55,34,32,11,19,17,54,66,13];
Sort(numbs);
function Sort(nums) {
var evens = [];
var odds = [];
//alert(arguments.length); // for debugging
for (var i = 0; i < nums.length; i++) { // nums.length per commentary below
//for (var i = 0; i < arguments.length; i++) {
if (nums[i]%2){
odds.push(nums[i]); // odds, not evens per commentary below
//evens.push(nums[i]);
}
else {
evens.push(nums[i]); // evens, not odds per commentary below
//odds.push(nums[i]);
}
}
alert(evens.toString());
alert(odds.toString());
}
arguments.length is the number of arguments passed to the function, not the length of the array passed as a single argument in this case (i.e. arguments[0].length); further, there is little reasons to use the arguments array at all when you can refer to a named parameter (i.e. nums).
Also, your evens/odds logic is flip-flopped.
You were pretty close you just have to make a couple of changes
The first change needs is to change the arguments.length to nums.length since you are passing the array as a parameter you are using its length.
The second change needed is to change the following in your if then statement:
nums[i] % 2
to:
nums[i] % 2 === 0
Currently you are not storing even numbers in your evens array.
javascript:
var numbs = [1,2,34,54,55,34,32,11,19,17,54,66,13];
Sort(numbs);
function Sort(nums) {
var evens = [];
var odds = [];
for (var i = 0; i < nums.length; i++) {//<---change number 1
if (nums[i] % 2 === 0){ //<--- change number 2 if the remainder = 0 it is even
evens.push(nums[i]);
}
else {
odds.push(nums[i]);
}
}
alert(evens.toString());
alert(odds.toString());
}
Try the following code, it takes the array, numbs, and sorts it and inserts the odd numbers in the odd array, and the even numbers into the even array:
var numbs = [1,2,34,54,55,34,32,11,19,17,54,66,13];
Sort(numbs);
var evens = [];
var odds = [];
function Sort(nums) {
for (var i = 0; i < nums.length; ++i) {
if ((nums[i] % 2) === 0) {
evens.push(nums[i]);
}
if ((nums[i] % 2) == 1) {
odds.push(nums[i]);
}
}
alert(evens);
alert(odds);
}

Categories

Resources