I am trying to create a function that changes positions of the items inside an array.
For example, I have this array:
[1, 2, 3] - if I call the function I get this => [2, 3, 1];
If I call the function again I should have this => [3, 1, 2];
The next time it should move again and so on.
But instead, if I call the function a second time I get this again => [2, 3, 1];
How could I make this work properly?
I know why this is happening, every time I call the function it receives the same values in the same order, I get that, that's why I built another array (move) to receive the values in the current order, it was an attempt to use this new array the second time I call the function, I tried it using an if/else statemente, but it didn't work; I also built another function passing 'move' as a parameter, and it worked, but just doesn't make any sense I have to have a different function for every move.
p.s. I am receiving the values from a HTML input.
<input id="numero1" value="">
<button onclick="moveLeft()">Move</button>
var n1 = document.getElementById("numero1");
function moveLeft() {
var str = n1.value;
var arr = str.split('');
var move = [];
console.log(arr);
arr.splice(0, 3, arr[1], arr[2], arr[0]);
console.log(arr);
for (var i = 0; i < arr.length; i++) {
move.push(arr[i]);
}
console.log(move);
teste(move);
}
function teste(move) {
console.log(move);
move.splice(0, 3, move[1], move[2], move[0]);
console.log(move);
}
If I understood properly, I think you can simplify in one line function:
const moveLeft = (arr) => arr.push(a.shift());
Notice that this function would mutate the content of the array but I guess that what you want:
const array = [1, 2, 3];
moveLeft(array);
console.log(array)// [2, 3, 1]
moveLeft(array);
console.log(array)// [3, 1, 2]
moveLeft(array);
console.log(array)// [1, 2, 3]
Basically with push we add a new element at the end of the array, and the new element we add, is the return value of the method shift, that removes the first element from an array and return it.
Edit
If you don't want to mutate the original array, the fastest way is create a shallow copy and pass that to the function:
const newArray = array.slice();
moveLeft(newArray);
console.log(newArray, array) // [2, 1, 3] [1, 2, 3]
However, a possible implementation that always return a new array, could be:
const moveLeft = (arr) => [...arr.slice(1), arr[0]]
Just for future reference. But keep in mind that here you're create a shallow copy, (so one new array) and returns a new array from the spread operator, so it's less ideal. It could be useful only if you're writing an API that never allow mutability.
Edit 2
As per comment, the input's value should reflect the new order, so, given the moveLeft function written before (the first one, that mutates the content):
<input id="numero1" value="">
<button onclick="inputMoveLeft('numero1')">Move</button>
And the JS:
function inputMoveLeft(id) {
const input = document.getElementById(id);
input.value = moveLeft(input.value.split("")).join("");
}
It should give you the result you were looking for.
pop and shift sound like the thing you need:
function rotateLeft(array){
let first = array.shift()
array.push(first); // add to end
return array;
}
function rotateRight(array){
let last = array.pop()
array.unshift(last); // add to front
return array;
}
Related
map() can't mutate the calling array, instead it returns a new Array with modified values.
But, the following code mutating the original Array, is there any wrong in my understanding?
const arr = [1, 2, 3, 4, 5];
arr.map((num, index, arr1) => {
return arr1[index] = num * 2;
});
console.log(arr); // [2, 4, 6, 8, 10]
Well, you're mutating the original array by passing its reference into the callback function inside map() (arr1) and then manually accessing the indices. It will create a new array if you just return the value from that function.
const arr = [1, 2, 3, 4, 5];
const arr1 = arr.map((num) => {
return num * 2;
});
console.log(arr); // [1, 2, 3, 4, 5]
console.log(arr1); // [2, 4, 6, 8, 10]
The third argument to the callback function of map is the
original/source array on which the map is called upon
The arr and arr1 are both same i.e both are referencing on the same array, You can see it by using console.log(arr === arr1). So what ever you operation perform on the arr1, it gonna affect the arr.
const arr = [1, 2, 3, 4, 5];
arr.map((num, index, arr1) => {
console.log(arr1 === arr);
return num * 2;
});
You can just return num * 2 from the callback function. map internally creates a new array and return it. So you don't have to assign it as
arr1[index] = num * 2
You can also make it one-liner as:
arr.map((num, index, arr1) => num * 2)
const arr = [1, 2, 3, 4, 5];
const result = arr.map((num, index, arr1) => {
return num * 2;
});
console.log(arr); // [2, 4, 6, 8, 10]
console.log(result); // [2, 4, 6, 8, 10]
Array.map creates a new array populated with the results of calling a provided function on every element in the calling array.
Here its specifed that you must call or execute a function on every element of calling array.
What is the issue with your code?
You are not actually calling a function, you are instead updating the original array. If you are looking to create a new array by multiplying each node of the element with 2, you should do something like below.
Working Example
const arr = [1, 2, 3, 4, 5];
const newArray = arr.map((nodeFromOriginalArray, indexOfCurrentElement, arrayFromMapCalled) => {
return nodeFromOriginalArray * 2;
});
console.log(arr);
console.log(newArray);
Lets debug the paremeters inside the map function.
Here we have provided three arguments.
First argument nodeFromOriginalArray: The current element being processed in the array. This will be each node from your calling array.
Second argument indexOfCurrentElement: The index of the current element being processed in the array. Which means, the index of current element in calling array.
Third argument arrayFromMapCalled: The array map was called upon. This is the array on which the map function is getting executed. Please note, this is the original array. Updating properties inside this array results in updating your calling array. This is what happened in your case.
You should not modify your original array, which is the third parameter. Instead, you should return your node multipled by 2 inside map and assign this to a new array. Updating the third paramater inside the map function will mutate your calling array.
When calling map on an array, you provide a mapper with three arguments, an item in the array, it's index and the array itself (as you've represented in your snippet).
map takes the value returned by the function mapper as the element at the index in a new array returned by the operation.
const arr = [1,2,3,4,5]
const doubled = arr.map(x => x * 2) // [2,4,6,8, 10]
A over simplified implementation of map (without the index and originalArray params) might look like this. Let's assume that instead of being a method on the array instance, it's a function that takes an array and a mapper function.
I would not recommend re-implementing in production code, there's the native implementation as well as several libraries such as lodash and underscore that implement it.
function map(arr, mapper) {
const result = [];
for (const item of arr) {
const resultItem = mapper(item);
result.push(resultItem);
}
return result;
}
function double(x) {
return x * 2;
}
const doubled = map([1,2,3,4,5,6], double); // [2, 4, 6, 8 ,10, 12]
I have a function that reverses an array:
function reverseArray(array) {
for(let i = 0; i <= Math.floor(array.length / 2); i++) {
let old = array[array.length - 1 - i];
array[array.length - 1 - i] = array[i];
array[i] = old;
}
return array;
}
and a function that creates an local scope array and push values in reversed order:
function reverseArr(arr) {
let output = [];
for(let i of arr) {
output.unshift(i);
}
arr = output;
return arr;
}
Suppose there is an element:
let arrayValue = [1, 2, 3, 4, 5];
If i invoke the first function with arrayValue as argument, arrayValue is changed:
reverseArray(arrayValue); // [5, 4, 3, 2, 1]
console.log(arrayValue); // [5, 4, 3, 2, 1]
However if i invoke the second function with arrayValue:
reverseArr(arrayValue); //[5, 4, 3, 2, 1]
console.log(arrayValue); //[1, 2, 3, 4, 5]
arrayValue is not changed even if i assigned the reversed value to the argument before return:
arr = output;
can someone explain me why?
thanks in advance.
Basically you take a new array with
let output = [];
and later you assign the new array to the parameter arr
arr = output;
Now you have two object references, one arr of the outer scope and a new one of output.
To overcome this, you need to keep the object reference of array. For getting a new content in an existing array, you could empty the array and push the values of the new array.
arr.length = 0;
arr.push(...output);
When you do arr = output in reverseArr you are referring to a new array. In other words arrayValue in the outer context and arr refer to two different objects.
You cannot change the value of the variable the function is called with. If you have a reference to the object you can mutate it, but you cannot make the outside variable refer to another object.
Basically, your first function reverses the list in-place (i.e. operates on the list itself directly, without building a new list), while the second function reverses the list out-of-place, by building a new list which contents are the reverse of the original list.
When working in-place, the changes you do to array inside the function are directly applied to arrayValue.
The reason why arr = output does not work the way you intend is pretty much what the other answers refer to. Namely, arr and arrayValue are two different references ("pointers"). Initially, both arrayValue and arr "point to" the same array when the function is called. However, arr = output makes arr point to the newly built list output instead.
I am supposed to rotate an array of integers clockwise in JS.
Here is my code for it:
function rotateArray(N, NArray)
{
//write your Logic here:
for(j=0;j<2;j++){
var temp=NArray[N-1];
for(i=0;i<N-1;i++){
NArray[i+1]=NArray[i];
}
NArray[0]=temp;
}
return NArray;
}
// INPUT [uncomment & modify if required]
var N = gets();
var NArray = new Array(N);
var temp = gets();
NArray = temp.split(' ').map(function(item) { return parseInt(item, 10);});
// OUTPUT [uncomment & modify if required]
console.log(rotateArray(N, NArray));
The code accepts an integer N which is the length of the array. The input is as follows:
4
1 2 3 4
The correct answer for this case is supposed to be
4 1 2 3
But my code returns
4 1 1 1
I cannot find where my code is going wrong. Please help me out.
All you need to do is move one item from the end of the array to the beginning. This is very simple to accomplish with .pop() (removes an item from the end of an array), then declare a new array with that element as the first:
function rotateArray(N, NArray) {
const lastItem = NArray.pop();
return [lastItem, ...NArray];
}
console.log(rotateArray(1, [1, 2, 3, 4]));
Doing anything else, like using nested loops, will make things more unnecessarily complicated (and buggy) than they need to be.
If you don't want to use spread syntax, you can use concat instead, to join the lastItem with the NArray:
function rotateArray(N, NArray) {
const lastItem = NArray.pop();
return [lastItem].concat(NArray);
}
console.log(rotateArray(1, [1, 2, 3, 4]));
If you aren't allowed to use .pop, then look up the last element of the array by accessing the array's [length - 1] property, and take all elements before the last element with .slice (which creates a sub portion of the array from two indicies - here, from indicies 0 to the next-to-last element):
function rotateArray(N, NArray) {
const lastItem = NArray[NArray.length - 1];
const firstItems = NArray.slice(0, NArray.length - 1);
return [lastItem].concat(firstItems);
}
console.log(rotateArray(1, [1, 2, 3, 4]));
function rotate(array,n){
Math.abs(n)>array.length?n=n%array.length:n;
if(n<0){
n=Math.abs(n)
return array.slice(n,array.length).concat(array.slice(0,n));
}else{
return array.slice(n-1,array.length).concat(array.slice(0,n-1));
}
}
console.log(rotate([1, 2, 3, 4, 5],-3));
The answer by #CertainPerformance is great but there's a simpler way to achieve this. Just combine pop with unshift.
let a = [1,2,3,4];
a?.length && a.unshift(a.pop());
console.log(a);
You need to check the length first so you don't end up with [undefined] if you start with an empty array.
I have an array of objects that some of them are the same (duplicate).
in a loop of .forEach(). inside a callback function i want to remove a duplicate object when they enter to another array one by one. i tried to loop every iteration on the array to find and remove duplicate but for some reason i can not get it.
I tried to make a loop and slice the duplicate.
I can not make a function.
I can not get the whole array and handle the duplicates.
.forEach(function(snap){
groupsJoin.push({groupId: snap)}
groupsJoin.sort((a, b) => (a.groupId > b.groupId) ? -1 : 1)
for (z=1; z<groupsJoin.length; z++) {
if (groupsJoin[z-1].groupId === groupsJoin[z].groupId) {
groupsJoin = groupsJoin.slice(0, z)
}
...Object.assign({}, groupsJoin)
}
You could use the Set data structure. Just create a new Set by passing the array and it will automatically remove duplicates
let set1 = new Set(yourArray)
For more information, see the documentation
In case you can't use new Set(groupsJoin) to filter all of them at once, you refer to the following solution :
var groupsJoin = new Set();
arr.forEach(x => groupsJoin.add(x))
As result, you'll get an array with unique values.
if there is need to keep maps inside, instead of x, use
x.groupId => groupsJoin.add(x.groupId)
It will depend on your context.
var arr = [1, 2, 4, 5, 5, 4, 3, 9, 8, 11, 1];
var groupsJoin = new Set();
arr.forEach( x => groupsJoin.add(x));
console.log(groupsJoin);
Let's say I'm given an array. The length of this array is 3, and has 3 elements:
var array = ['1','2','3'];
Eventually I will need to check if this array is equal to an array with the same elements, but just twice now. My new array is:
var newArray = ['1','2','3','1','2','3'];
I know I can use array.splice() to duplicate an array, but how can I duplicate it an unknown amount of times? Basically what I want is something that would have the effect of
var dupeArray = array*2;
const duplicateArr = (arr, times) =>
Array(times)
.fill([...arr])
.reduce((a, b) => a.concat(b));
This should work. It creates a new array with a size of how many times you want to duplicate it. It fills it with copies of the array. Then it uses reduce to join all the arrays into a single array.
The simplest solution is often the best one:
function replicate(arr, times) {
var al = arr.length,
rl = al*times,
res = new Array(rl);
for (var i=0; i<rl; i++)
res[i] = arr[i % al];
return res;
}
(or use nested loops such as #UsamaNorman).
However, if you want to be clever, you also can repeatedly concat the array to itself:
function replicate(arr, times) {
for (var parts = []; times > 0; times >>= 1) {
if (times & 1)
parts.push(arr);
arr = arr.concat(arr);
}
return Array.prototype.concat.apply([], parts);
}
Basic but worked for me.
var num = 2;
while(num>0){
array = array.concat(array);
num--}
Here's a fairly concise, non-recursive way of replicating an array an arbitrary number of times:
function replicateArray(array, n) {
// Create an array of size "n" with undefined values
var arrays = Array.apply(null, new Array(n));
// Replace each "undefined" with our array, resulting in an array of n copies of our array
arrays = arrays.map(function() { return array });
// Flatten our array of arrays
return [].concat.apply([], arrays);
}
console.log(replicateArray([1,2,3],4)); // output: [1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3]
What's going on?
The first two lines use apply and map to create an array of "n" copies of your array.
The last line uses apply to flatten our recently generated array of arrays.
Seriously though, what's going on?
If you haven't used apply or map, the code might be confusing.
The first piece of magic sauce here is the use of apply() which makes it possible to either pass an array to a function as though it were a parameter list.
Apply uses three pieces of information: x.apply(y,z)
x is the function being called
y is the object that the function is being called on (if null, it uses global)
z is the parameter list
Put in terms of code, it translates to: y.x(z[0], z[1], z[2],...)
For example
var arrays = Array.apply(null, new Array(n));
is the same as writing
var arrays = Array(undefined,undefined,undefined,... /*Repeat N Times*/);
The second piece of magic is the use of map() which calls a function for each element of an array and creates a list of return values.
This uses two pieces of information: x.map(y)
x is an array
y is a function to be invoked on each element of the array
For example
var returnArray = [1,2,3].map(function(x) {return x + 1;});
would create the array [2,3,4]
In our case we passed in a function which always returns a static value (the array we want to duplicate) which means the result of this map is a list of n copies of our array.
You can do:
var array = ['1','2','3'];
function nplicate(times, array){
//Times = 2, then concat 1 time to duplicate. Times = 3, then concat 2 times for duplicate. Etc.
times = times -1;
var result = array;
while(times > 0){
result = result.concat(array);
times--;
}
return result;
}
console.log(nplicate(2,array));
You concat the same array n times.
Use concat function and some logic: http://www.w3schools.com/jsref/jsref_concat_array.asp
Keep it short and sweet
function repeat(a, n, r) {
return !n ? r : repeat(a, --n, (r||[]).concat(a));
}
console.log(repeat([1,2,3], 4)); // [1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3]
http://jsfiddle.net/fLo3uubk/
if you are inside a loop you can verify the current loop index with the array length and then multiply it's content.
let arr = [1, 2, 3];
if(currentIndex > arr.length){
//if your using a loop, make sure to keep arr at a level that it won't reset each loop
arr.push(...arr);
}
Full Example:
https://jsfiddle.net/5k28yq0L/
I think you will have to write your own function, try this:
function dupArray(var n,var arr){
var newArr=[];
for(var j=0;j<n;j++)
for(var i=0;i<arr.length;i++){
newArr.push(arr[i]);
}
return newArr;
}
A rather crude solution for checking that it duplicates...
You could check for a variation of the length using modulus:
Then if it might be, loop over the contents and compare each value until done. If at any point it doesn't match before ending, then it either didn't repeat or stopped repeating before the end.
if (array2.length % array1.length == 0){
// It might be a dupe
for (var i in array2){
if (i != array1[array2.length % indexOf(i)]) { // Not Repeating }
}
}