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;
}
}
Related
This question already has answers here:
How to randomize (shuffle) a JavaScript array?
(69 answers)
Closed 3 years ago.
var arr = [1, 2, 3, 4];
finalarr = [];
for (i = 0; i <= 5; i++) {
arr.sort(function(a, b) {
return 0.5 - Math.random();
});
finalarr.push(arr);
}
/*once it randomizes that first array, it keeps repeating it. i dont want
that i want it to reshuffle the array everytime i run that loop*/
console.log(finalarr);
It randomizes the array only once and keeps repeating it
Edit
The second demo is Demo 1 modified to accept two parameters:
#Params: array [Array]...: The array to shuffle
repeat [Number]..: The number of new randomized arrays to be returned
#Return: An array of arrays (aka "two-dimensional array")
As mentioned by Nick Parsons, you are using a reference to the array plus your result is a full array in which you are adding to an empty array (ex. [[4, 3, 2, 1]]) a more practical return would be just an array with the same elements as the original array but in a random order ([2, 4, 1, 3]).
The following demo:
Uses the most effective way to shuffle an array: Fisher–Yates algorithm.
Accepts a standard array and clones it by the spread operator [...array]
The shuffle() function is called three separate times and returns a new array with a randomized order.
Note: There's an optional utility function that just displays console logs nicer. It is not a requirement.
Demo 1
let array = [1, 2, 3, 'A', 'B', 'C'];
const shuffle = ([...array]) => {
let i = 0;
let j = 0;
let temp = null;
for (i = array.length - 1; i > 0; i -= 1) {
j = Math.floor(Math.random() * (i + 1));
temp = array[i];
array[i] = array[j];
array[j] = temp;
}
return array;
}
const log = data => console.log(JSON.stringify(data));
log(shuffle(array));
log(shuffle(array));
log(shuffle(array));
Demo 2
let array = [1, 2, 3, 'A', 'B', 'C'];
const shuffle = (array, repeat = 1) => {
let result = [];
for (let r = repeat; r > 0; r -= 1) {
let clone = [...array];
for (let i = clone.length - 1; i > 0; i -= 1) {
let s = Math.floor(Math.random() * (i + 1));
let temp = clone[i];
clone[i] = clone[s];
clone[s] = temp;
}
result.push(clone);
}
return result;
}
const log = data => console.log(JSON.stringify(data));
log(shuffle(array));
log(shuffle(array, 5));
// .flat() is invoked on the return array to provide a single array
log(shuffle(array, 5).flat());
You just need to dereference the arr before pushing. Any of following three would work.
var arr = [1, 2, 3, 4];
finalarr = [];
for (i = 0; i <= 5; i++) {
arr.sort(function(a, b) {
return 0.5 - Math.random();
});
finalarr.push(Object.assign({},arr));
}
console.log(finalarr);
var arr = [1, 2, 3, 4];
finalarr = [];
for (i = 0; i <= 5; i++) {
arr.sort(function(a, b) {
return 0.5 - Math.random();
});
finalarr.push({...arr});
}
console.log(finalarr);
var arr = [1, 2, 3, 4];
finalarr = [];
for (i = 0; i <= 5; i++) {
arr.sort(function(a, b) {
return 0.5 - Math.random();
});
finalarr.push(JSON.parse(JSON.stringify(arr)));
}
console.log(finalarr);
Attach an array literal to the sort function, and push the result to the final array.
let finalarr = []
for (i = 0; i <= 5; i++) {
let arr = [1, 2, 3, 4].sort(function(a, b) {
return 0.5 - Math.random()
})
finalarr.push(arr)
}
console.log(finalarr)
The problem here is that you're adding a reference to the same array for each index. They're not all their own arrays- they're all the exact same one. Imagine there are two newscasters, each reporting on the same story. If the story changes, both newscasters will tell you the same update. That's what these arrays are doing. When you say something like arr1 = arr2, you're just saying that arr1 is now a newscaster for the same story/value- so changing the value associated with one of them changes both of them, and shuffling one of them shuffles both of them. To change this, you need to clone the array before assigning it to a new variable.
Change:
finalarr.push(arr);
to:
finalarr.push(arr.slice(0));
Using .slice(0) on the array is a method to clone a shallow copy of the array (which will be sufficient for your code) so each one is actually its own value. Run this new version of your code here:
var arr = [1, 2, 3, 4];
finalarr = [];
for (i = 0; i <= 5; i++) {
arr.sort(function(a, b) {
return 0.5 - Math.random();
});
finalarr.push(arr.slice(0));
}
console.log(finalarr);
Personally, I choose to use randojs.com to grab shuffled arrays. It grabs a new, independent array each time you call randoSequence, so no funny business to worry about with references. Your code would look like this with randojs:
var finalarr = [];
for (var i = 0; i <= 5; i++) finalarr.push(randoSequence(1, 4));
console.log(finalarr);
<script src="https://randojs.com/1.0.0.js"></script>
Yes, you can use javascript array shuffle function to randomly shuffle your array.
like in your code,
var arr=[1,2,3,4]
finalarr = [];
var shuffle_arr=shuffle(arr);
finalarr.push(shuffle_arr);
just use the shuffle function.
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.
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)
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]));
I want to extract some element while removing the element by condition in Array.
My code is pretty ugly and I have no idea which will be better way for readability and performance
ex)
there is array like
a =[1,2,3,4,3,2,2,2,1]
I want extract element which is grater than 2 ( element >2 ). Then I will push it into new array until length of newArray is 2.
and I need last idx which index of element after loop break point in newArray
result will be
a = [1,2,2,2,2,1]
newArray = [3,4] (I want to keep order)
idx = 2
This is my code. But pretty ugly.
for (let i = 0; i < leng; i++) {
if (array[i]> cond) {
newArray.push(array[i])
array.splice(i, 1)
i -= 1
leng -= 1
if (newArray.length === cond) {
idx = i;
break;
}
}
}
For a little more readable code we can apply functional style.
let a =[1,2,3,4,3,2,2,2,1];
let b = [];
let idx = 0;
let filterFn = function (e) { if (b.length < 2 && e > 2) { b.push(e); ++idx; } return e <= 2; }
a.filter(filterFn);
I'd like to offer you some more faster variant of code
let arr = [1, 2, 3, 4, 3, 2, 2, 2, 1];
let newArr = [];
let max = arr.length;
let idx = 0;
let cond = 2;
let maxValue = 2;
while (cond && idx < max) {
let value = arr[idx];
if (value > maxValue) {
newArr.push(value);
arr.splice(idx, 1);
cond--;
continue;
}
idx++;
}
console.log(arr); // [1, 2, 3, 2, 2, 2, 1]
console.log(newArr); // [3, 4]
console.log(idx); // 2