Using Recursion in JavaScript to shift Array elements to different positions - javascript

I know this question has been asked a lot, but I've yet to find a solution that is in JavaScript (a lot of Java and C++) using recursion, and not new/old index splicing. This is merely an exercise and I'm not great at recursion, so any assistance and a thorough explanation would be greatly appreciated.
//given an array, shift all elements within the array forward 2 positions.
// [1, 2, 3, 4, 5] --> [4, 5, 1, 2, 3]
My first line of thought was to use a placeholder of some sort but I'm not sure what to do with it exactly. This is what I have so far
let array = [1, 2, 3, 4, 5];
function shiftTwo (arr) {
for (i=0; i<arr.length; i++) {
let curr = arr[0];
}
}
Thanks in advance!

One possibility is to recur on the number of spaces to move. If it's 0, return the array intact (or possibly clone it with arr.slice(0)); otherwise, shift the last entry to the front and recur with one less. The code might look like this:
const shiftRight = (n, arr) =>
n <= 0
? arr
: shiftRight (n - 1, [...arr.slice(-1), ...arr.slice(0, -1)])
console .log (shiftRight (2, [1, 2, 3, 4, 5]))

Here is a solution using recursion:
function shiftArr(arr, n) {
if (n<=0) {
return arr;
}
else{
arr.unshift(arr.pop());
return shiftArr(arr,n-1)
}
}
//test:
console.log(shiftArr([1, 2, 3, 4, 5],2)); // [4, 5, 1, 2, 3]

Related

How can I remove items from an array having met specific conditions in-place?

I am working on what i thought is a simple algorithm:
Task: Look at the given array, take only the even numbers and multiply them by 2. The catch is to modify the array in its place and NOT create a new array.
I can loop/map through an array and figure out what numbers are even, so
I got this far:
const arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
arr.forEach((x, y) => {
if (x % 2 !== 0) {
// I would like to splice those numbers,
// but can't figure out how to do it?
}
})
Again, the catch is that modifying the original array is not allowed, returning 4, 8, 12, 16, and 20.
This is not a good approach in my opinion, but if you insist on modifying the existing array without creating a new one, this should do the job:
const arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
let i = 0;
while (i < arr.length) {
if (arr[i] % 2 === 0) {
arr[i] *= 2;
} else {
arr.splice(i, 1);
i--;
}
i++;
}
console.log(arr.join(", "));
The i-- comes into play, because when you splice the current index (where the next element will be after the splice) and you execute i++, it's going to skip the current index. The same effect can possibly be achieved by adding i++ in the if block and remove the i-- in the else block.
First of all.
Why would you do that? If you don't want the old array just take the new one.
const arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
const evenNumbers = arr.filter(item => item % 2 === 0)
Unless it's something required, explore all Js Array methods, always are multiple ways to get to an answer. Try to make your life easy.
Like the example before you will have the old and the new. Take wherever you need.
You could take a different approach and loop from start by using a new index for all items to keep and later adjust the length of the array.
const
array = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
let l = 0; i = 0;
while (i < array.length) {
console.log(...array);
if (array[i] % 2 === 0) array[l++] = array[i] * 2;
i++;
}
array.length = l;
console.log(...array);
.as-console-wrapper { max-height: 100% !important; top: 0; }
You can use Array.prototype.filter() and Array.prototype.map()
Code:
const arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
const result = arr
.filter(n => n % 2 === 0)
.map(n => n * 2)
console.log(result)
Could this be what you had in mind?
const arr=[1,2,3,4,5,6,7,8,9,10];
for (let i=arr.length-1;i>=0;i--)
if(arr[i]%2>0) arr.splice(i,1)
arr.forEach((v,i,a)=> a[i]=v*2)
console.log(arr);
As you want to remove elements from an array you are looping over, it is important that you start from the end and work your way down to 0 since going forward you would skip an element as soon as you remove one.

Inserted array shows in reverse JS

I am just starting to learn js and as many (I'm sure) I am facing problems lol. I am trying to copy an array into another array at a designated index location.
I seem to be able to do everything correct but when I log the result, the inserted array shows in reverse and I have no idea why¿?¿?.
Have also tried a .forEach as looping method, but I'm still a bit green to use it right.
This is the code:
function frankenSplice(arr1, arr2, n) {
let newArr = arr2.slice([]);
for (let i = 0; i < arr1.length; i++) {
newArr.splice(n, 0, arr1[i]);
console.log(newArr)
}
}
frankenSplice([1, 2, 3], [4, 5, 6], 1);
It logs // [ 4, 3, 2, 1, 5, 6 ] instead of the desired out: [ 4, 1, 2, 3, 5, 6 ]
You are inserting the elements at the same index, so after inserting 1 you insert 2 at the same position, shifting back the 1 and all following elements.
Either iterate backwards over arr1 or increment n after each iteration like I have done here.
function frankenSplice(arr1, arr2, n) {
let newArr = arr2.slice([]);
for (let i = 0; i < arr1.length; i++) {
newArr.splice(n, 0, arr1[i]);
console.log(newArr)
n++; // add this
}
}
frankenSplice([1, 2, 3], [4, 5, 6], 1);

Finding and removing matching and corresponding values in an array

Here's a sample of the problem I'm having in JavaScript:
first array [1, 2, 3, 4, 5, 6, 7]
second array [7, 8, 9, 4, 2, 5, 7]
In this case, I need to be able to find and eliminate "4" and "7" from both arrays, eliminating both. This is based on their location and matching value.
I haven't been able to find anything other than eliminating matching values. In this case, however, the values must be in the same place and also be matching.
I've tried this so far:
function findCommonElements3(array1, array2) {
return arr1.some(item => arr2.includes(item))
}
it looks like it only looks for matching elements, whereas I need to find matching corresponding elements and then remove them.
As mentioned in the comments, you may use the splice method to remove one or more elements of an array in JavaScript.
First of all I would store the indexes of the elements I should remove looping the array as so:
const array1 = [1, 2, 3, 4, 5, 6, 7];
const array2 = [7, 8, 9, 4, 2, 5, 7];
//Indexes of same elements
var sameIndexes = [];
function findSameIndexes(element, index) {
if (array1[index] == array2[index]) {
sameIndexes.push(index);
}
}
array1.forEach(findSameIndexes);
Calling console.log(sameIndexes) should give this result:
Array [3, 6]
The problem is that if you loop again the array and remove the elements in that order, the indexes would not correspond to the elements anymore.
For example if you remove the 3rd element, the number 7 wouldn't be at index 6 anymore, to solve this issue I'd use the reverse method so you won't lose track of the indexes
// A simple function to remove the elements in both arrays
function removeElements(index) {
array1.splice(index,1);
array2.splice(index,1);
}
sameIndexes.reverse().forEach(removeElements);
And the final results would be
Array [1, 2, 3, 5, 6]
Array [7, 8, 9, 2, 5]
Which hopefully is what you were looking for, of course there are better ways to write it down, but maybe this will help you find a solution.
You could just use a for loop and use index. something like this
const firstarray = [1, 2, 3, 4, 5, 6, 7]
const secondarray = [7, 8, 9, 4, 2, 5, 7]
for (let i = 0; i <= firstarray.length - 1; i++) {
if (firstarray[i] === secondarray[i]) {
console.log(`found ${firstarray[i]} at index ${i}`);
firstarray.splice(i, 1);
secondarray.splice(i, 1);
}
}
console.log(firstarray, secondarray);
const excludeCommon = (ar1, ar2) => {
const both = [...ar1, ...ar2].filter((v, i, ar) => v !== ar[i + (2 * (i < ar1.length) - 1) * ar1.length]);
return [both.slice(0, both.length / 2), both.slice(both.length / 2)];
}
console.log(excludeCommon([1, 2, 3, 4, 5, 6, 7], [7, 8, 9, 4, 2, 5, 7]));

What's the most concise way in javascript to find consecutive dups in an array, sum them up and reiterate?

Example
I have an array of:
const myArr = [1, 1, 1, 3, 2, 2, 4, 3];
If I were pass it to the function it should produce the output like so:
//result: [2, 1, 3, 8, 3]
The consecutive first two 1s and 2s were consecutive duplicates so they were summed up.
The first two consecutive 1s became 2 so it now doesn't match.
The consecutive 2s became 4 so it matched the next running number and summed up again resulting in an 8
Although the 3s are duplicate they we're not summed up because they're not consecutive
Bonus
It would be great if someone can demonstrate this using javascript's array functions map or reduce.
Is this possible without any kind of recursion? someone mentioned its possible, then I'd be nice if it didn't use recursion
EDIT
Adding this here because some have already provided answers.
In the case of:
const myArr = [1, 1, 1, 1];
// result: [4]
const myArr = [1, 1, 1, 1, 3, 2, 2, 4, 3];
// result: [4, 3, 8, 3]
Another interesting case that didn't pass my mind:
const myArr = [1, 1, 2, 2];
//result [4, 2] instead of [2,4]
It should check against the new array as soon a change was made
With the assumption that this will be used only on arrays of numbers, this is simple enough to do with reduce.
function duplicateAddition(input) {
var last;
var result = input;
do {
last = result;
result = last.reduce(function (carry, item) {
if (carry[carry.length - 1] == item) {
carry[carry.length - 1] *= 2;
} else {
carry.push(item);
}
return carry;
}, []);
} while (last.length != result.length);
return result;
}
Assuming the array always contains numbers, the most concise I can think of would be
function merge(arr) {
var x = String(arr),
y = x.replace(/([^,]),\1/, (_,m)=>2*m);
return x.length == y.length ? y.split(",").map(Number) : merge(y);
}
If you want to avoid the tail recursion, it's trivial to convert that to a loop:
function merge(arr) {
var y = String(arr);
do {
var x = y;
y = x.replace(/([^,]),\1/, (_,m)=>2*m);
} while(x.length != y.length)
return y.split(",").map(Number);
}
or
function merge(arr) {
for (var x=String(arr), y=""; x.length!=y.length; x=y.replace(/([^,]),\1/, (_,m)=>2*m))
y=x;
return x.split(",").map(Number);
}
Btw, to alter the behaviour of the algorithm to get [2, 4] instead of [4, 2] from [1, 1, 2, 2] (i.e. find all duplicates and sum them before reiterating), you'd only need to add the /global flag to the regex.
This solution uses a recursive generator. It has the advantage that it pretty much says what it means and does what it says.
function* x([first, second, ...rest]) {
if (first !== undefined) {
if (first !== second) yield first; else second *= 2;
yield* x([second, ...x(rest)]);
}
}
function test(a) { console.log(Array.from(x(a))); }
test([1, 1, 1, 3, 2, 2, 4, 3]);
test([1, 1, 1, 1]);
test([1, 1, 2, 2]);
In this solution, the input [1, 1, 2, 2] produces [2, 4]. That is because the logic greedily collapses the 2, 2 into a 4, which then does not match the 2 resulting from 1, 1. If this behavior is not desired, then it might suffice to change the line above to:
yield* x([second, ...rest]);
This is a simple game of unshifting from array a to pushing array b. So if a[0] === a[1] you take the first two items from array a, get their sum and push it into array b but if a[0] !== a[1] then take only the first item and push it into array b. However before we push the interim value (t in below snippet) we check the last item of array b to see if it's equal to the interim. If they are equal we just double the last item of array b if not just push interim (t) over b.
Then make a tail call optimized recursive invoking.
function sumAndReduce(a, b = []){
var t = 0;
if (!a.length) return b;
t = a[0] === a[1] ? a.splice(0,2).reduce((p,c) => p+c)
: a.splice(0,1)[0];
b[b.length-1] === t ? b[b.length-1] += t
: b.push(t);
return sumAndReduce(a,b);
}
var myArr = [1, 1, 1, 3, 2, 2, 4, 3],
result = sumAndReduce(myArr);
console.log(JSON.stringify(result));
console.log(JSON.stringify(sumAndReduce([1, 1, 1, 1])));
console.log(JSON.stringify(sumAndReduce([1, 1, 2, 2])));
Well... if you don't want recursion even if it is a tail call optimized one, then it's very trivial to convert the above code into an iterative one with a while loop. I'll leave it to you..!
So i can not make sure if your request as per an input [1,1,2,2] breaks the initial conditions but here is a modified version of the above code to comply with that as well.
function sumAndReduce(a, b = []){
var t = 0;
if (!a.length) return b;
t = a[0] !== a[1] || b[b.length-1] === a[0] ? a.splice(0,1)[0]
: a.splice(0,2).reduce((p,c) => p+c);
b[b.length-1] === t ? b[b.length-1] += t
: b.push(t);
return sumAndReduce(a,b);
}
var myArr = [1, 1, 1, 3, 2, 2, 4, 3],
result = sumAndReduce(myArr);
console.log(JSON.stringify(result));
console.log(JSON.stringify(sumAndReduce([1, 1, 1, 1])));
console.log(JSON.stringify(sumAndReduce([1, 1, 2, 2])));

Bonfire Seek and Destroy- Freecodecamp Challenge

You will be provided with an initial array (the first argument in the destroyer function), followed by one or more arguments. Remove all elements from the initial array that are of the same value as these arguments.
I've these instructions:
destroyer([1, 2, 3, 1, 2, 3], 2, 3) should return [1, 1].
destroyer([1, 2, 3, 5, 1, 2, 3], 2, 3) should return [1, 5, 1].
destroyer([3, 5, 1, 2, 2], 2, 3, 5) should return [1].
destroyer([2, 3, 2, 3], 2, 3) should return [].
destroyer(["tree", "hamburger", 53], "tree", 53) should return ["hamburger"].
I've found code:
function destroyer(arr) {
var args = Array.prototype.slice.call(arguments);
args.splice(0,1);
return arr.filter(function(element) {
return args.indexOf(element) === -1;
});
}
My questions:
Can you explain this code in English, please?
Can you give a shortcut code for above challenge? please.
I've done this challenge using filter function, though t is recommended to use also 'indexOf' in order to compare value in array by the value to filter with.
````
function destroyer(arr) {
// Remove all the values
var temp = [];
for (var i = 1; i < arguments.length; i++) {
temp.push(arguments[i]);
arr = arguments[0].filter(function(value) {
return ( value !== temp[i - 1]) ;
});
}
return arr;
}
destroyer([1, 2, 3, 1, 2, 3], 2, 3);
````
function destroyer(arr) {
var args = arr.slice.call(arguments);
args.splice(0,1);
return arr.filter(function(element) {
return args.indexOf(element) === -1;
});
}
line 1 declares the overall function used for the challenge
line 2 converts the arguments of arr into a array variable named args, although this method doesn't work when optimizing in certain javascript platforms (optimization is basically what you're trying to do with your second question)
line 3 removes zero (0) and one (1) from args
lines 4 and 5 return the final result (true/false) of filtering arr for falsy and truthy by seeing whether or not an element of arg is present in arr, returning -1 if not and the element's location in arr if true
this is actually relatively optimized; there is much more more-optimized code but oftentimes it is only viable on certain javascript platforms (mozilla javascript, etc.)

Categories