Duplicate an array an arbitrary number of times (javascript) - javascript

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 }
}
}

Related

Leetcode Rotate Array works differently in codepen [duplicate]

This question already has answers here:
Rotate the elements in an array in JavaScript
(42 answers)
Closed 2 months ago.
I've solved one of Leetcode problems in codepen, but when I try to submit it on leetcode I get a different result than what I get in codepen.
The problem is:
Given an array, rotate the array to the right by k steps, where k is non-negative.
Example 1:
Input: nums = [1,2,3,4,5,6,7], k = 3
Output: [5,6,7,1,2,3,4]
Explanation:
rotate 1 steps to the right: [7,1,2,3,4,5,6]
rotate 2 steps to the right: [6,7,1,2,3,4,5]
rotate 3 steps to the right: [5,6,7,1,2,3,4]
Link (requires login) https://leetcode.com/explore/interview/card/top-interview-questions-easy/92/array/646/
My solution:
var rotate = function(nums, k) {
var a = nums.splice(0 , nums.length-k);
var b = nums.splice(-k);
var c = [...b , ...a ];
return(c);
};
Using the above example, running this code on codepen returns (or console.logs) [5,6,7,1,2,3,4].
But when I run this code in leetcode, I get an empty array [].
Any ideas why this could be the happening?
It looks like you're supposed to rotate the original array, not return a new rotated array. So you need to set nums = [...b, ...a] instead.
EDIT: Since JavaScript passes by value, the nums parameter just holds a reference to the original array, so doing nums = [] will only change the nums variable to reference a different array, without changing the original array. You'll want to call methods of the original array to mutate it. E.g. .splice
/EDIT
Also, have you thought about what happens when k is greater than the length of the array? E.g. nums = [1, 2, 3], k = 5
Also also, your link to leetcode requires login, so not everyone will be able to view it.
Example A
.pop() removes the last element of an array and returns it. .unshift() the returned value of .pop() to the first index of the array. Do that k times in a for loop. .pop() and .unshift() changes (aka mutates) the original array.
let arr = [1, 2, 3, 4, 5, 6, 7], k = 3;
function rotate(array, times) {
for (let i=0; i < times; i++) {
let last = array.pop();
array.unshift(last);
}
return array;
}
console.log(rotate(arr, k));
Example B
By changing .splice() to .slice() you can implement your logic since .slice() creates a shallow copy of the array and does not mutate the original array like .splice(). Since the original array is unchanged, any references to said array are consistent. Also, concerning the case mentioned in LawrenceWebDev's answer -- if k is greater than the length of the array -- k (times) becomes the remainder of k/array.length (times % size).
let arr = [1, 2, 3, 4, 5, 6, 7], k = 3;
function rotate(array, times) {
const size = array.length;
if (times > size) {
times = times % size;
}
let a = array.slice(-times);
let b = array.slice(0, size - times);
return [...a, ...b];
}
console.log(rotate(arr, k));

Array, return original index from a sorted array in javascript

'I wish to sort an array in numerical order but once it is sorted I wish to be able to find the original index.
For example the original array:
ptsGP = [3,8,2,5,6,9,8,4]
I am using the following code below to sort the array:
arr = ptsGP;
var arr2 = arr.map(function(o, i){return {idx: i, obj: o}; }).sort(function(a, b) {
return b.obj - a.obj;
});
for(var i = 1, j = arr2.length; i <= j; i++){
document.write('i:' + i + ' = arr2[i].obj: PTS: ', arr2[i-1].obj+"<br/>");
}`
This is fine as the sorted array is :
arr = [2,3,4,5,6,8,8,9];
How can I find the index of sorted number in the original array? In this case it would be :
Index on original array would be = [2,0,7,3,4,1,6,5]
I know I could use map on the original array but how can I deal with duplicate numbers i.e, in this case I have two number 8's within the array?
You can achieve it by following below steps :
Creating a deep copy of an original array by using spread operator. So that we can get proper indexing.
Now we can iterate deep copy array to get the index of the elements from an original array.
Regarding duplicate values we can check via .indexOf() and .lastIndexOf() methods.
via and then via comparison. For fetching the correct index of duplicate values I wrote a logic based on the count of duplicate value.
Working Demo :
// Original array.
const originalArray = [3, 8, 2, 5, 6, 9, 8, 4];
// Creating a deep copy of an original array.
const deepCopy = [...originalArray].sort(function(a, b){
return a-b
});
// result array
const arr = [];
// count to get the index based on duplicate values.
let count = 0;
// Iterating deepCopy array to get the actual index.
deepCopy.forEach((elem) => {
// Checking for duplicate value in an array
if (originalArray.indexOf(elem) === originalArray.lastIndexOf(elem)) {
// This line of code execute if there is no duplicates in an array.
arr.push(originalArray.indexOf(elem))
} else {
// This line of code execute if there is duplicate values in an array.
count++;
// Inserting the index one by one.
arr.push(originalArray.indexOf(elem, count))
}
});
// Result array.
console.log(arr);

Spinning the elements of an array clockwise in JS

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.

When looping through values of a JS array, and I remove value, do I need to use while instead of for?

var myArray = [1,2,3,4,5,6,7,8,9];
function isOdd(value){
return value % 2;
}
for(var i = 0; i < myArray.length; i++){
if(isOdd(myArray[i])){
myArray.splice(i,1);
i--;
}
}
The code above takes an array of arbitrary length and checks each value. If the value of the bit of the array meets an arbitrary condition (in this case if it is odd), then it is removed from the array.
Array.prototype.splice() is used to remove the value from the array, and then i is decremented to account for the rest of the values in the array "moving down" to fill in the gap that the removed value left (so the loop doesn't skip over a value).
However, the for loop ends when i equals the length of the array, which gets shorter as values are removed.
Does the value of myArray.length decrease dynamically as the loop proceeds, or does it save the value at the start of the loop and not update as values are removed? If the latter, what can I do to fix my loop?
Thank you!
myArray.length is changing with the operation on the array. But looping and splicing leads to unwanted results, if not proper padded.
To prevent unnecessary corrections, use a while loop from the end, to keep the rest of the array for processing.
function isOdd(value) {
return value % 2;
}
var myArray = [1, 2, 3, 4, 5, 6, 7, 8, 9],
i = myArray.length;
while (i--) {
if (isOdd(myArray[i])) {
myArray.splice(i, 1);
}
}
console.log(myArray);
The length property is read in every iteration, and the splice method does update its value, so it works as you would expect. However, I would say that this is not a good coding practice, a while loop is much more readable, so it should be the obvious choice.
To answer the question directly: you don't have to use while instead of for, but you definitely should.
Use Array.filter instead
var myArray = [1,2,3,4,5,6,7,8,9];
myArray=myArray.filter(function(item,index) {
return !(item % 2);
})
console.log(myArray)
This is where you'd want to use Array.prototype.filter() if you don't absolutely HAVE to modify the original array, in-place.
As you suspect, the .length property of the array is being updated every time you splice(). The filter() method was built for exactly this sort of operation.
var myArray = [1,2,3,4,5,6,7,8,9];
function isOdd(value){
return value % 2;
}
var filteredArray = myArray.filter(function(item){
return !isOdd(item);
});
console.log(filteredArray);
A more concise version of the above code:
var myArray = [1,2,3,4,5,6,7,8,9];
function isEven(value){
return value % 2 === 0;
}
var filteredArray = myArray.filter(isEven);
console.log(filteredArray);
An even more concise version relying on ES6 arrow syntax:
var myArray = [1,2,3,4,5,6,7,8,9];
var isEven = value => value % 2 === 0;
var filteredArray = myArray.filter(isEven);
console.log(filteredArray);
And, in the event that you absolutely MUST edit the array in-place / use splice() here, I would recommend using Array.prototype.forEach() over a for or while loop. forEach() is another higher order method that allows you to realize the same functionality with less boilerplate. As with most higher order methods/functions, it allows you to focus on defining what you need to do rather than exactly how it needs to be done.
var myArray = [1,2,3,4,5,6,7,8,9];
function isOdd(value){
return value % 2;
}
myArray.forEach(function(c, i, a){
if(isOdd(c)){
a.splice(i,1);
}
})
console.log(myArray);
You can use both of them and it's depends on which one you like. if you prefer to use while loop then Nina's answer looks good and if you want to use for loop then consider to manage counter changes by yourself completely or when the length changes:
function isOdd(value) {
return value % 2;
}
var arr1 = [1, 2, 3, 4, 5, 6, 7, 8, 9];
for (var i = 0; i < arr1.length;)
isOdd(arr1[i]) ? arr1.splice(i, 1) : i++;
console.log(arr1);
var arr2 = [1, 2, 3, 4, 5, 6, 7, 8, 9];
for (var i = 0; i < arr2.length; i++)
if (isOdd(arr2[i])) {
arr2.splice(i, 1);
i--;
}
console.log(arr2);

Undo sort on sorted array in javascript

I have an array. I sort it.
I get a second array which is already sorted based on the first one.
I need to reverse the sorting on the second array.
For example, if the first array (unsorted) is: [9, 5, 3, 0, 2] then I want to to sort it, so that it becomes [0, 2, 3, 5, 9].
Then I receive the second array sorted based on the first one, for example ["home", "car", "train", "pc", "mouse"]. I need it to become ["mouse, "pc", "train", "home", "car"].
I can't make a copy of the array.
I have the following code:
//data_r is an array with values
var i = 0;
var sort_order = new Array();
data_r.sort(function (a,b) {
var res = a[0] - b[0];
sort_order[i] = res;
i++;
return res;
});
In the end, the the sort_order array will contain the actions performed when we sorted items. If I want to sort a second array exactly the same way as the first then I can do the following:
//data_x is an array with values
var i = 0;
data_x.sort(function (a,b) {
i++;
return sort_order[i-1];
});
Now the data_x array is sorted exactly the same way as the data_r array.
How can I undo sort on the data_r array?
The following code is incorrect:
var unsort = new Array();
for(var i = 0; i < data_r.length; i++)
unsort[i] = sort_order[i]*(-1);//-1 so we perfom the oposite action
Your premise here is flawed.
In the end, the sort_order array contains the actions performed when we sorted items.
No, it doesn't; it contains a log of the comparisons performed by the Javascript Array.sort function. The actions it took in response to those comparison results are private to it.
If I want to sort a second array exactly the same way as the first then I can do the following:
This is not guaranteed to work. Even if the two arrays are the same size, Array.sort may not always compare the same elements in the same order each time it's called - it's possible that it's using a randomized algorithm, that it performs comparisons based on other data that are internal to the interpreter, or that it switches between multiple entirely different sort algorithms under some circumstances.
While this code may work for you, right now, in your current web browser, it is likely to fail in surprising ways in other circumstances (possibly in future browsers). Do not use this technique in production code.
The question is, how can i unsort the data_r array?
Make a copy of the array before you sort it.
Storing res[i] = a - b is like journaling the sort() algorithm - but what if it used a random pivot?
This code is inherently unreliable unless you write sort() yourself. It's also inefficient.
A better approach, one that will solve both your needs, is to create an array of indices and sort that. This is trivial to invert. Then you can implement a permute function that takes an array of indices, and it achieves a sort or unsort, depending on the input.
If x is from 0:n-1, create an array sort_i of same size, then initialize each sort_i[i] = i.
for(var i = 0; i < n; i++)
sort_i[i] = i;
Then
sort_i.sort(function (a,b) { return x[a] - x[b]; });
Now you have the indices. To apply to x:
for(var i = 0; i < n; i++)
sort_x[i] = x[sort_i[i]];
To unsort it, first invert the indices
for(var i = 0; i < n; i++)
unsort_i[sort_i[i]] = i;
Then apply the indices. Exercise left to question asker.
This approach of sorting an array of integer indices is needed when you don't want to move the original elements around in memory (maybe they are big objects), and many other circumstances. Basically you are sorting pointers. The result is an index to the data, and a reverse index.
See #duskwuff's answer on why your approach doesn't work.
Instead, just introduce a mapping between the original data and the sorted data.
{0:2, 1:3, 2:1, 3:0}
Which means the first element became the third, the second became the last and so on. Below we'll use an array instead of an object.
Why does this map help? You can sort it like another dataset by just using the indizes in it as pointers to the data you're going to compare. And you can apply the mapping easily on other datasets. And you can even reverse that mapping very easily. See it in the code:
// data_r, data_x are arrays with values
var l = data_r.length;
var sort_order = new Array(l);
for (var i=0; i<l; i++) sort_order[i] = i; // initialised as 1-1 mapping
// change the sort_order first:
sort_order.sort(function (a,b) {
// a and b being indices
return data_r[a] - data_r[b];
});
// Making a new, sorted array
var data_x_sorted = new Array(l);
for (var i=0; i<l; i++)
data_x_sorted[ sort_order[i] ] = data_x[i]; // put it to sorted position
If you want to sort the data_x array itself, just use the "apply" algorithm which I showed for data_r.
The question is, how can I undo sort on the data_r array?
Either don't sort it at all, and just make a copy of it which gets sorted (or do nothing at all).
Or use the sort_order to reverse it. You just would need to swap i and newIndex (sortOrder[i]) everywhere. Example for building a new, "unsorted" (old-order) array:
var unsorted = new Array(l);
for (var i=0; i<l; i++)
unsorted[i] = data_r[ sort_order[i] ]; // take it from its new position
While this question is 8 years old at this point, I came across it when trying to find the same solution to the problem and I was unable to find a suitable, performant, and intuitive way of doing so, so I wrote one myself.
Please take a look at the sort-unwind library. If ranks is a list of indexes that would rank an array in order...
import unwind from 'sort-unwind'
const suits = ['♥', '♠', '♣', '♦']
const ranks = [2, 0, 3, 1]
const [sortedSuits, tenet] = unwind(ranks, suits)
// sortedSuits <- ['♠', '♦', '♥', '♣']
// unwind <- [1, 3, 0, 2]
You can then use the tenet variable that's returned to unsort an array and restore the original ordering.
const names = ['spades', 'diamonds', 'hearts', 'clubs']
const [tenetNames, tenetRanks] = unwind(tenet, names)
// tenetNames <- ['hearts', 'spades', 'clubs', 'diamonds']
// tenetRanks <- [2, 0, 3, 1]
The sort function just returns a number which can be positive,zero, or negative telling it if the current element goes before,has same weight, or goes after the element it is comparing it too. I would imagine your sort order array is longer than your data_r array because of the number of comparisons you make. I would just make a copy of data_r before you sort it and then set data_r equal to that array when you want it unsorted.
If you have a lot of these arrays to maintain, it might be as well to
convert array1 into an array of objects, each one containing the value
and its original position in the array. This keeps everything together
in one array.
var array1 = [9, 5, 3, 0, 2];
var array2 = ["home", "car", "train", "pc", "mouse"];
var sort = function(array){
var indexed_objects = array.map(function(value, index){
return {index: index, value: value};
});
indexed_objects.sort(function(a,b){
return a.value <= b.value ? -1 : 1;
});
return indexed_objects;
};
var sorted1 = sort(array1);
sorted1; // [{index: 3, value:0}, {index: 4, value: 2}, ...]
And now, given an array of sorted objects, we can write a function to
unsort any other array accordingly:
var unsort = function(array, sorted_objects){
var unsorted = [];
sorted_objects.forEach(function(item, index){
unsorted[item.index] = array[index];
});
return unsorted;
};
var array2_unsorted = unsort(array2, sorted1);
array2_unsorted; // ["mouse", "pc", "train", "home", "car"]
v1 = [0,1,2,3,4,5,6]
q = v1.length
b = []
for(i=0;i<q;i++){
r = parseInt(Math.random()*v1.length)
b.push(v1[r])
a = v1.indexOf(v1[r])
v1.splice(a,1)
}

Categories

Resources