javascript unshift pop in a loop - javascript

I'm studying JS and I have this exercise that is asking to reverse an array in place (without the use of a second array) and without the use of 'reverse'. Although I already have the solution to the exercise I don't understand why my solution does not work, here it is:
function reverseArrayInPlace (arr){
const k = arr[0];
while (arr[arr.length-1] !== k){
arr.unshift(arr.pop());
}
return arr;
}
console.log(reverseArrayInPlace(arr1));

You take the end of the array and put it at the first position:
[1, 2, 3]
[3, 1, 2]
[2, 3, 1]
[1, 2, 3]
as you can see that actually doesnt reverse anything.

It will not work if your array contains duplicates of the first element.
As you are taking the first element as key, whenever any duplicate element becomes the last element, your loop exits.

Try this, just check if the two elements being selected is equal or not, if equal do not swap else swap. Iterate till the pointer k is <= the pointer j.
function reverseArrayInPlace (arr){
let first = 0;
let last = arr.length - 1;
let k = first, j = last;
while(k <= j){
if(arr[k] !== arr[j]){
let temp = arr[k];
arr[k] = arr[j];
arr[j] = temp;
}
k++;
j--;
}
return arr;
}
arr1 = [1, 2, 3, 4];
console.log(reverseArrayInPlace(arr1));
arr1 = [1, 2, 3];
console.log(reverseArrayInPlace(arr1));

This method will solve the problem without pop or unshift. Try this.
function reverseArray(array) {
for (let i = 0; i < Math.floor(array.length / 2); i++) {
let oldArray = array[i];
array[i] = array[array.length - 1 - i];
array[array.length - 1 - i] = oldArray;
}
return array;
}
console.log(reverseArray([1,2,3]));

Related

Why does my sort implementation not work?

I'm trying to sort an integer array without using sort function. I know there are other solutions available on Stack Overflow. I want to know what is wrong with my code. It performs ascending sort except for the first number in the array.
let arr = [2,4,5,1,3,7];
let iterable = true;
let iterationCount = 0;
while(iterable) {
for(var i=iterationCount;i<=arr.length;i++) {
if (arr[i] > arr[i+1]) {
let temp=arr[i];
arr[i]=arr[i+1];
arr[i+1]=temp;
}
}
iterationCount++;
if (iterationCount == arr.length) {
iterable = false;
}
}
console.log(arr)
The output is [2, 1, 3, 4, 5, 7] while it should be [1, 2, 3, 4, 5, 7].
You could change the outer loop for keeping the last index for checking and iterate until before the last index, because in the first inner loop, the max value is now at the greatest index and any further iteration do not need to check the latest last item.
let array = [2, 4, 5, 1, 3, 7],
iterationCount = array.length;
while (iterationCount--) {
for (let i = 0; i < iterationCount; i++) {
if (array[i] > array[i + 1]) {
let temp = array[i];
array[i] = array[i + 1];
array[i + 1] = temp;
}
}
}
console.log(array);
Each time it goes around the inner loop, it moves each element zero or one spaces to the left.
Each time it goes around the outer loop, it ignores one more element from the left hand side.
This means that it assumes that after one loop the left most element is the smallest element (and after two loops, the two left most elements are the two smallest).
However, because of (1) the 1 will have moved from position 3 to position 2 but it needs to be in position 0.
Wikipedia has a selection of popular sorting algorithms you should read up on if you are implementing sorting from scratch.
I fixed the for loop to always start at 0, then it works.
let arr = [2, 4, 5, 1, 3, 7];
for (let j = 0; j < arr.length; j++) {
for (let i = 0; i < arr.length; i++) {
if (arr[i] > arr[i + 1]) {
const temp = arr[i];
arr[i] = arr[i + 1];
arr[i + 1] = temp;
}
}
}
console.log(arr)
EDIT: I made the whole thing a little shorter

How to write my reverse function properly?

i have a problem and i need help for this question.
My reverse function doesn't work the way I want it to.
function reverseArrayInPlace(array){
let old = array;
for (let i = 0; i < old.length; i++){
array[i] = old[old.length - 1 - i];
};
};
let arrayValue = [1, 2, 3, 4, 5];
reverseArrayInPlace(arrayValue);
console.log(arrayValue);
I expect on [5, 4, 3, 2, 1] but i have [5, 4, 3, 4, 5].
Why does it work this way? Please help me understand.
P.S I know about the reverse method.
Variable, with assigned object (array, which is a modified object in fact) - stores just a link to that object, but not the actual object. So, let old = array; here you just created a new link to the same array. Any changes with both variables will cause the change of array.
(demo)
let arr = [0,0,0,0,0];
let bubu = arr;
bubu[0] = 999
console.log( arr );
The simplest way to create an array clone:
function reverseArrayInPlace(array){
let old = array.slice(0); // <<<
for (let i = 0; i < old.length; i++){
array[i] = old[old.length - 1 - i];
};
return array;
};
console.log( reverseArrayInPlace( [1, 2, 3, 4, 5] ) );
P.s. just for fun:
function reverseArrayInPlace(array){
let len = array.length;
let half = (len / 2) ^ 0; // XOR with 0 <==> Math.trunc()
for( let i = 0; i < half; i++ ){
[ array[i], array[len - i-1] ] = [ array[len - i-1], array[i] ]
}
return array;
};
console.log( reverseArrayInPlace( [1, 2, 3, 4, 5] ) );
If you're writing a true in place algorithm, it's wasteful from both a speed and memory standpoint to make an unnecessary copy (as other answers point out--array and old are aliases in the original code).
A better approach is to iterate over half of the array, swapping each element with its length - 1 - i compliment. This has 1/4 of the iterations of the slice approach, is more intuitive and uses constant time memory.
const reverseArrayInPlace = a => {
for (let i = 0; i < a.length / 2; i++) {
[a[i], a[a.length-1-i]] = [a[a.length-1-i], a[i]];
}
};
const a = [1, 2, 3, 4, 5];
reverseArrayInPlace(a);
console.log(a);
Since this is a hot loop, making two array objects on the heap just to toss them out is inefficient, so if you're not transpiling this, you might want to use a traditional swap with a temporary variable.
function reverseArrayInPlace(a) {
for (var i = 0; i < a.length / 2; i++) {
var temp = a[i];
a[i] = a[a.length-i-1];
a[a.length-i-1] = temp;
}
};
var a = [1, 2, 3, 4];
reverseArrayInPlace(a);
console.log(a);
You have in old variable the same array (not by value, but by reference), so if you change any of them you'll have changes in both.
So you should create new array, make whatever you want with them and return it (or just copy values back to your origin array if you don't want to return anything from your function).
It happend like that because:
1) arr[0] = arr[4] (5,2,3,4,5)
2) arr[1] = arr[3] (5,4,3,4,5)
....
n) arr[n] = arr[0] (5,4,3,4,5)
So you can just make a copy (let old = array.slice()) and it'll be woking as you'd expect.

Behaviour of i inside the for-loop isn't what I was expecting

I already solved the problem below using reverse() and push() but I wanted to also solve it using a for..loop just for the sake of my own learning and I'm glad I did because I'm discovering some odd behaviour that I'm hoping somebody can explain and point out to me.
I'm so baffled at the result I'm getting when I return the new array. I'm getting the correct length but it's the values of the new array that's making me scratch my head. It's as if i is not incrementing on the left-hand side of the assignment statement.
Thanks in advance for your time! : )
Here's the problem
// Write a function called unshift which accepts an array and a value and adds the value to the beginning of the array. This function should return the new length of the array.
// Do not use the built in Array.unshift() function!
const arr = [1, 2, 3];
unshift(arr, 0); // return value is 4, the length of the array
// arr; // [0, 1, 2, 3]
// unshift([4, 5, 6, 7], 10); // return value is 5, the length of
the array
// arr; // [10,4,5,6,7]
I've tried using a temporary variable
function unshift(arr, val) {
let currVal
arr.length = arr.length + 1 // adds an addition position to the
array
for (let i = 0; i < arr.length - 1; i++) { // my loop condition
currVal = arr[i] // not behaving as expected
arr[i + 1] = currVal // value never seems to increment
}
arr[0] = val
return arr // I'm returning the arr rather than its length for
now
}
This is the solution I thought would work...
function unshift(arr, val) {
arr.length = arr.length + 1 // adds an addition position to the array
for (let i = 0; i < arr.length - 1; i++) { // my loop condition
arr[i + 1] = arr[i] // arr[i] is not behaving as expected
}
arr[0] = val
return arr // I'm returning the arr rather than its length for now
}
This is what I'm expecting it to do:
const arr = [1, 2, 3];
unshift(arr, 0); // 4
// arr; // [0, 1, 2, 3]
But this is what's happening:
unshift(arr, 0); // 4
// arr; // [0,1,1,1] // ??? It's as if arr[i] isn't incrementing
With
for (let i = 0; i < arr.length - 1; i++) { // my loop condition
arr[i + 1] = arr[i] // arr[i] is not behaving as expected
you're starting at index 0 and overwriting index i + 1 with the value at index i on every iteration. So, the result is that the array is full of copies of the item originally at index 0 (except for the new value assigned to index 0 at the very end).
Iterate backwards instead, from the array's .length down to 0, so you don't lose information due to overwriting:
function unshift(arr, val) {
for (let i = arr.length; i >= 0; i--) {
arr[i] = arr[i - 1];
}
arr[0] = val;
return arr.length;
}
const arr = [1, 2, 3];
const newLength = unshift(arr, 0);
console.log(newLength);
console.log(arr);
Note that there's no need to assign a new .length to the array - assigning to the indicies alone is sufficient.
Use push and reverse.
const unshift = (arr, val) => (arr.reverse(), arr.push(val), arr.reverse()).length;
You overwrite the actual value. If you like to keep the approach, you need to store the last value and assign the value in the loop.
function unshift(arr, val) {
var item = arr[0];
arr.length = arr.length + 1;
for (let i = 1; i < arr.length; i++) {
[item, arr[i]] = [arr[i], item]; // swap values
}
arr[0] = val;
return arr.length;
}
const arr = [1, 2, 3];
console.log(unshift(arr, 0)); // 4
console.log(arr); // [0, 1, 2, 3]
An easier approach is to loop from the end.
function unshift(array, value) {
var i = array.length;
while (i--) {
array[i + 1] = array[i];
}
array[0] = value;
return array.length;
}
const arr = [1, 2, 3];
console.log(unshift(arr, 0)); // 4
console.log(arr); // [0, 1, 2, 3]
You can use for when ever you have something to do with the items in the array. Make sure not to use it if there is no need to use it. This is because of some performance issues.
var arr = [1, 2, 3];
function unshift(arr, val) {
arr.unshift(val) // add value at the first position of the array
console.log(arr) // show updated array in the console
return arr.length // return length of the array
}
unshift(arr, 0)

Writing my own reverse array function without defining a new empty array

I am trying to write a function which reverses the elements of an array without defining a new empty array in the function.
let arrayValue = [1, 2, 3, 4, 5]
function remove(array, index) {
return array.slice(0, index).concat(array.slice(index + 1));
}
function reverseArrayInPlace(array) {
for (i = array.length - 2; i >= 0; i--) {
let removedCharacter = array[i];
array = array.concat(removedCharacter);
array = remove(array, i);
}
return array;
}
When I console.log(reverseArrayInPlace(arrayValue)) I am getting the reverse order of [5, 4, 3, 2, 1].
However when I try to just do reverseArrayInPlace(arrayValue) and then console.log(arrayValue), I am getting [1, 2, 3, 4, 5] which is the value defined at the beginning.
Is there a way of updating the arrayValue binding in the function and then when it is console.log outside the function, it is showing the reversed order?
// show cases of even and odd lengths
const x = [1,2,3,4];
const y = [1,2,3,4,5];
for (let i = 0; i < x.length / 2; i++) {
const tmp = x[i];
x[i] = x[x.length - 1 - i];
x[x.length - 1 - i] = tmp;
}
for (let i = 0; i < y.length / 2; i++) {
const tmp = y[i];
y[i] = y[y.length - 1 - i];
y[y.length - 1 - i] = tmp;
}
console.log(x);
// [4, 3, 2, 1]
console.log(y);
// [5, 4, 3, 2, 1]
The MDN docs for Array's slice and concat methods explain that these methods return new arrays, rather than modifying the existing arrays. If you are looking for a built-in Array method for modifying arrays, splice will do the job. However, it's going to be more complicated to implement this using splice than to just use a for loop as the other answers suggest.
You could just swap values symmetrically around the midpoint of the array, like
const arr = [0,1,2,3,4];
const len = arr.length;
for(let i = 0; i < len/2; i++){
let temp = arr[i];
arr[i] = arr[len-1-i];
arr[len-1-i] = temp;
}
console.log(arr);
function reverseArrayInPlace(array) {
for (let i = 0; i < array.length / 2; i++) {
const oppositeArrayIndex = array.length - (i + 1);
const oppasiteArrayValue = array[oppositeArrayIndex];
array[oppositeArrayIndex] = array[i];
array[i] = oppasiteArrayValue;
}
}

how do I return new array every time I swap 2 values?

I'm working on some quiz and I have an array which is looking like this one: let a = [1, 3, 4, 2]
Now I'm wondering how do I create a loop that returns three new arrays with 2 swapped values i.e: (a[i] swapped with a[i+1])
I'm expecting to get 3 following arrays like below:
[3, 1, 4, 2]
[1, 4, 3, 2]
[1, 3, 2, 4]
What would be the approach creating the loop for this? I have been trying to loop through the array with map function and swapping values but found that I'm just confusing myself. Any constructive approach/solution with an explanation to this quiz would be appreciated.
map in a loop is all you should need
let a = [1, 3, 4, 2];
let r = [];
for (let i = 0; i < a.length - 1; i++) {
r[i] = a.map((v, index) => {
if(index == i) return a[i+1];
if(index == i + 1) return a[i];
return v;
});
}
console.log(r);
Using a simple for loop:
let a = [1, 3, 4, 2],
result = [];
for(let i = 0; i < a.length - 1; i++) { // notice that the loop ends at 1 before the last element
let copy = a.slice(0); // copy the array
let temp = copy[i]; // do the swaping
copy[i] = copy[i + 1];
copy[i + 1] = temp;
result.push(copy); // add the array to result
}
console.log(result);

Categories

Resources