I need to push array of elements inside another array at a particular index in javascript without using spread operator and without using another array.
Input:
let firstArray = [4,5,6];
let secondArray = [1,2,3,7,8,9];
Expected Output:
console.log(secondArray); //[1,2,3,4,5,6,7,8,9];
I tried using splice and apply function like below.
let firstArray = [4,5,6];
let secondArray = [1,2,3,7,8,9];
firstArray.splice(0, 0, 3, 0);
secondArray.splice.apply(secondArray, firstArray);
This code gives expected output but also updating the elements in firstArray before updating the secondArray.
Is there any better way to achieve the expected output without updating the elements in firstArray?
Edit 1:
I am trying to achieve this without new array because the size of the firstArray and secondArray are huge. Thus feeling it might create unwanted memory allocation for new array to just push elements into another array.
Avoiding spread operator as it is not supported in IE browsers
Edit 2:
Removed without using loops condition.
You've said your reason for the constraints is:
...because the size of the firstArray and secondArray are huge. Thus feeling it might create unwanted memory allocation for new array to just push elements into another array.
That being the case, you want to avoid that .splice(0, 0, 3, 0) on firstArray, since it requires moving everything in firstArray over to make room for the elements.
Your memory issue doesn't explain the prohibition on using a loop (after all, splice uses a loop) and copyWithin (also a loop) combined with a loop to fill in the new elements would be a clean, simple, and not memory-intensive way to solve the problem. So:
function insert(target, source, index) {
// Get the count of elements to copy
let count = source.length;
if (count) {
// 1. First, make room by copying elements out of the way
let targetIndex = index + source.length;
target.length += count;
target.copyWithin(targetIndex, index, index + count);
// 2. Now, fill in the new elements
while (count-- > 0) {
target[targetIndex--] = source[count];
}
}
return target;
}
Live Example:
let firstArray = [4,5,6];
let secondArray = [1,2,3,7,8,9];
function insert(target, source, index) {
// Get the count of elements to copy
let count = source.length;
if (count) {
// 1. First, make room by copying elements out of the way
let targetIndex = index + source.length;
target.length += count;
target.copyWithin(targetIndex, index, index + count);
// 2. Now, fill in the new elements
while (count-- > 0) {
target[targetIndex--] = source[count];
}
}
return target;
}
insert(secondArray, firstArray, 3);
console.log(JSON.stringify(secondArray)); // [1,2,3,4,5,6,7,8,9];
console.log(JSON.stringify(firstArray)); // [4,5,6];
If the while loop seems a bit opaque to you, you can also write the loop part of that like this:
for (let index = 0; index < count; ++index) {
target[targetIndex + index] = source[index];
}
Live Example:
let firstArray = [4,5,6];
let secondArray = [1,2,3,7,8,9];
function insert(target, source, index) {
// Get the count of elements to copy
let count = source.length;
if (count) {
// 1. First, make room by copying elements out of the way
let targetIndex = index + source.length;
target.length += count;
target.copyWithin(targetIndex, index, index + count);
// 2. Now, fill in the new elements
for (let index = 0; index < count; ++index) {
target[targetIndex + index] = source[index];
}
}
return target;
}
insert(secondArray, firstArray, 3);
console.log(JSON.stringify(secondArray)); // [1,2,3,4,5,6,7,8,9];
console.log(JSON.stringify(firstArray)); // [4,5,6];
Note that copyWithin is probably not supported by IE11, but is easily polyfilled.
Related
Please note: the linked question, "How can I create every combination possible for the contents of two arrays?" does not solve this particular question. The persons that labeled that did not fully understand this specific permutation and request.
If you have two arrays (arr1, arr2) with n elements in each array (i.e., each array will be the same length), then the question is: What's the best method to get/determine all the possible matches where elements do not match with other elements in the same array and where order does not matter?
For example, let's say I have:
arr1 = ["A","B","C"];
arr2 = ["Z","Y","X"];
I would like to get back an array of arrays where each element of one array is paired with an element of another array. So the result would be a unique set of arrays:
matches = [
[["A","Z"],["B","Y"],["C","X"]],
[["A","Z"],["B","X"],["C","Y"]],
[["A","Y"],["B","X"],["C","Z"]],
[["A","Y"],["B","Z"],["C","X"]],
[["A","X"],["B","Z"],["C","Y"]],
[["A","X"],["B","Y"],["C","Z"]],
]
Please note, these two arrays would be the same:
[["A","Z"],["B","Y"],["C","X"]]
[["B","Y"],["C","X"],["A","Z"]]
I am trying to do this with vanilla JavaScript but am completely open to using Lodash as well. For an added bonus, since this can get out of control, speed and performance are important. But right now, I am just trying to get something that would yield a proper result set. To limit this, this function would probably not be used with more than two arrays of 50 elements each.
Here is my latest attempt (using lodash):
function getMatches(arr1, arr2){
var matches = [];
for (var arr1i = 0, arr1l = arr1.length; arr1i < arr1l; arr1i++) {
for (var arr2i = 0, arr2l = arr2.length; arr2i < arr2l; arr2i++) {
matches.push(_(arr1).zip(arr2).value());
arr2.push(arr2.shift());
}
}
return matches;
}
[[A, 1], [B, 2]]
is the same as
[[B, 2], [A, 1]]
in your case, which means that the solution depends on what you pair to the first elements of your array. You can pair n different elements as second elements to the first one, then n - 1 different elements as second elements to the second one and so on, so you have n! possibilities, which is the number of possible permutations.
So, if you change the order of the array elements but they are the same pair, they are equivalent, so you could view the first elements as a fixed ordered set of items and the second elements as the items to permutate.
Having arr1 = [a1, ..., an] and arr2 = [b1, ..., bn] we can avoid changing the order of a1. So, you permutate the inner elements and treat the outer elements' order as invariant, like:
const permutations = function*(elements) {
if (elements.length === 1) {
yield elements;
} else {
let [first, ...rest] = elements;
for (let perm of permutations(rest)) {
for (let i = 0; i < elements.length; i++) {
let start = perm.slice(0, i);
let rest = perm.slice(i);
yield [...start, first, ...rest];
}
}
}
}
var other = ['A', 'B', 'C'];
var myPermutations = permutations(['X', 'Y', 'Z']);
var done = false;
while (!done) {
var next = myPermutations.next();
if (!(done = next.done)) {
var output = [];
for (var i = 0; i < next.value.length; i++) output.push([other[i], next.value[i]]);
console.log(output);
}
}
You're just looking for permutations. The first elements of your tuples are always the same, the second ones are permuted so that you get all distinct sets of combinations.
const arr1 = ["A","B","C"];
const arr2 = ["Z","Y","X"];
const result = permutate(arr2).map(permutation =>
permutation.map((el, i) => [arr1[i], el])
);
This implementation uses Typescript and Lodash.
const permutations = <T>(arr: T[]): T[][] => {
if (arr.length <= 2)
return arr.length === 2 ? [arr, [arr[1], arr[0]]] : [arr];
return reduce(
arr,
(acc, val, i) =>
concat(
acc,
map(
permutations([...slice(arr, 0, i), ...slice(arr, i + 1, arr.length)]),
vals => [val, ...vals]
)
),
[] as T[][]
);
};
I am creating a function that will accept two parameters, which are each arrays, and return a separate array of matching values between the two arrays.
I made two versions of the function,
Defaults to iterate through the first parameter in a for
loop, and checks the second parameter for a matching value using .includes()
ex:
var matches = [];
for (let i = 0, len = array1.length; i < len; i++) {
var a = array1[i];
if (array2.includes(a)) {
matches.push(a)
}
Measures and compares the lengths of the two arrays, and chooses
the shorter array to iterate through in the for loop
ex:
if (array1.length <= array2.length) {
var itArr = array1;
var checkArr = array2 }
else { var itArr = array2
var checkArr = array1 };
var matches = [];
for (let i = 0, len = itArr.length; i < len; i++) {
var a = itArr[i];
if (checkArr.includes(a)) {
matches.push(a)
}
My question is whether or not this actually improves the performance, or makes no difference, or harms the performance (by adding more variable definitions, calculations, etc.)?
It wouldn't make significant difference since the worst case complexity would be O(n*m) where n and m are the length of the arrays.
You can sort the 2 arrays and find the intersection using 2 pointers, The time complexity in that case would be O(nlogn + mlogm + n + m) subject to the sorting algorithm used
I think I would go for the first approach, due to the .includes function will try to iterate the array and return true when it finds the element, so if the element is in the end of the array it iterates completely on it. Hence your attempt for chosing the small one shouldn't make too much difference.
Here is an example of using a Set for seeing if one array contains values from the other.
If your not ES6, (and why not?), you could use a simple object literal.
This should be faster than doing a double for loop, as that's kind of what includes would be doing.
function makeRandom(count, max) {
return Array.from(new Array(count),
(a,ix) => Math.round(Math.random() * max));
}
function union(a,b) {
var aSet = new Set(a), oSet = new Set();
b.forEach((v) => { if(aSet.has(v)) oSet.add(v) });
return Array.from(oSet);
}
const
random1 = makeRandom(5, 10),
random2 = makeRandom(5, 10);
const
unionArray = union(random1, random2);
console.log(random1.join(':'));
console.log(random2.join(':'));
console.log(unionArray.join(':'));
Could you please help me figure out this algorithm without using splice:
Write a program that inserts a new number A at an index B. For example, if array = [1, 3, 5, 7] and A = 10 and B = 2, by the end of your program, array should be [1, 3, 10, 5, 7].
My thinking is that I would loop through the array, and then replace A with B, but it's not quite right:
for(var i = 0; i < arr.length; i++) {
arr[2] = 10;
}
Without using .splice you still have quite a few options. Let's look at a single, simple example for now.
This solution involves using a reverse loop, and adjusting our indices manually to insert a single value. This alters the original array.
You can see here we are just shifting our next values into our current position, which starts at the index that is equivalent to our length. Then we can slot our new value in the final index.
function insert (array, index, value) {
var i = array.length;
while (i > index) {
array[i] = array[--i]; // Prefix is important.
}
array[i] = value; // Or array[index], i === index at this point.
return array;
}
console.log(insert([1,2,3,4], 2, 'B'));
This only inserts a single element into the array. Can you figure out how to insert multiple elements starting from the index?
If you are allowed to use .slice and .concat you can emulate an inserting .splice. This returns a new array.
function insert (array, index, value) {
return array.slice(0, index).concat(value, array.slice(index));
}
console.log(insert([1,2,3,4], 2, 'B'));
Since inserting affects the length of the array, one approach is to start moving elements from the end to their current position + 1, then when the required index is reached, insert the new element.
Using a decrementing for loop:
function slowSplice(array, element, index) {
for (var i=array.length; i>index; i--) {
array[i] = array[i-1];
}
array[index] = element;
}
Using a decrementing while loop:
function slowSplice2(array, element, index) {
var i = array.length;
while (i > index) {
array[i] = array[--i];
}
array[index] = element;
}
Note that the above assumes a contiguous array. If sparse arrays must be accommodated, more work is required. If the function is required to be implemented as a general function, the splice algorithm from ECMA-262 should be followed.
I have this:
var arr = [0, 21, 22, 7];
What's the best way to return the index of the highest value into another variable?
This is probably the best way, since it’s reliable and works on old browsers:
function indexOfMax(arr) {
if (arr.length === 0) {
return -1;
}
var max = arr[0];
var maxIndex = 0;
for (var i = 1; i < arr.length; i++) {
if (arr[i] > max) {
maxIndex = i;
max = arr[i];
}
}
return maxIndex;
}
There’s also this one-liner:
let i = arr.indexOf(Math.max(...arr));
It performs twice as many comparisons as necessary and will throw a RangeError on large arrays, though. I’d stick to the function.
In one line and probably faster then arr.indexOf(Math.max.apply(Math, arr)):
var a = [0, 21, 22, 7];
var indexOfMaxValue = a.reduce((iMax, x, i, arr) => x > arr[iMax] ? i : iMax, 0);
document.write("indexOfMaxValue = " + indexOfMaxValue); // prints "indexOfMaxValue = 2"
Where:
iMax - the best index so far (the index of the max element so far, on the first iteration iMax = 0 because the second argument to reduce() is 0, we can't omit the second argument to reduce() in our case)
x - the currently tested element from the array
i - the currently tested index
arr - our array ([0, 21, 22, 7])
About the reduce() method (from "JavaScript: The Definitive Guide" by David Flanagan):
reduce() takes two arguments. The first is the function that performs the reduction operation. The task of this reduction function is to somehow combine or reduce two values into a single value, and to return that reduced value.
Functions used with reduce() are different than the functions used with forEach() and map(). The familiar value, index, and array values are passed as the second, third, and fourth arguments. The first argument is the accumulated result of the reduction so far. On the first call to the function, this first argument is the initial value you passed as the
second argument to reduce(). On subsequent calls, it is the value returned by the previous invocation of the function.
When you invoke reduce() with no initial value, it uses the first element of the array as the initial value. This means that the first call to the reduction function will have the first and second array elements as its
first and second arguments.
Another solution of max using reduce:
[1,2,5,0,4].reduce((a,b,i) => a[0] < b ? [b,i] : a, [Number.MIN_VALUE,-1])
//[5,2]
This returns [5e-324, -1] if the array is empty. If you want just the index, put [1] after.
Min via (Change to > and MAX_VALUE):
[1,2,5,0,4].reduce((a,b,i) => a[0] > b ? [b,i] : a, [Number.MAX_VALUE,-1])
//[0, 3]
To complete the work of #VFDan, I benchmarked the 3 methods: the accepted one (custom loop), reduce, and find(max(arr)) on an array of 10000 floats.
Results on chromimum 85 linux (higher is better):
custom loop: 100%
reduce: 94.36%
indexOf(max): 70%
Results on firefox 80 linux (higher is better):
custom loop: 100%
reduce: 96.39%
indexOf(max): 31.16%
Conclusion:
If you need your code to run fast, don't use indexOf(max).
reduce is ok but use the custom loop if you need the best performances.
You can run this benchmark on other browser using this link:
https://jsben.ch/wkd4c
If you are utilizing underscore, you can use this nice short one-liner:
_.indexOf(arr, _.max(arr))
It will first find the value of the largest item in the array, in this case 22. Then it will return the index of where 22 is within the array, in this case 2.
Unless I'm mistaken, I'd say it's to write your own function.
function findIndexOfGreatest(array) {
var greatest;
var indexOfGreatest;
for (var i = 0; i < array.length; i++) {
if (!greatest || array[i] > greatest) {
greatest = array[i];
indexOfGreatest = i;
}
}
return indexOfGreatest;
}
var arr=[0,6,7,7,7];
var largest=[0];
//find the largest num;
for(var i=0;i<arr.length;i++){
var comp=(arr[i]-largest[0])>0;
if(comp){
largest =[];
largest.push(arr[i]);
}
}
alert(largest )//7
//find the index of 'arr'
var arrIndex=[];
for(var i=0;i<arr.length;i++){
var comp=arr[i]-largest[0]==0;
if(comp){
arrIndex.push(i);
}
}
alert(arrIndex);//[2,3,4]
EDIT: Years ago I gave an answer to this that was gross, too specific, and too complicated. So I'm editing it. I favor the functional answers above for their neat factor but not their readability; but if I were more familiar with javascript then I might like them for that, too.
Pseudo code:
Track index that contains largest value. Assume index 0 is largest initially. Compare against current index. Update index with largest value if necessary.
Code:
var mountains = [3, 1, 5, 9, 4];
function largestIndex(array){
var counter = 1;
var max = 0;
for(counter; counter < array.length; counter++){
if(array[max] < array[counter]){
max = counter;
}
}
return max;
}
console.log("index with largest value is: " +largestIndex(mountains));
// index with largest value is: 3
function findIndicesOf(haystack, needle)
{
var indices = [];
var j = 0;
for (var i = 0; i < haystack.length; ++i) {
if (haystack[i] == needle)
indices[j++] = i;
}
return indices;
}
pass array to haystack and Math.max(...array) to needle. This will give all max elements of the array, and it is more extensible (for example, you also need to find min values)
If you create a copy of the array and sort it descending, the first element of the copy will be the largest. Than you can find its index in the original array.
var sorted = [...arr].sort((a,b) => b - a)
arr.indexOf(sorted[0])
Time complexity is O(n) for the copy, O(n*log(n)) for sorting and O(n) for the indexOf.
If you need to do it faster, Ry's answer is O(n).
A minor modification revised from the "reduce" version of #traxium 's solution taking the empty array into consideration:
function indexOfMaxElement(array) {
return array.reduce((iMax, x, i, arr) =>
arr[iMax] === undefined ? i :
x > arr[iMax] ? i : iMax
, -1 // return -1 if empty
);
}
A stable version of this function looks like this:
// not defined for empty array
function max_index(elements) {
var i = 1;
var mi = 0;
while (i < elements.length) {
if (!(elements[i] < elements[mi]))
mi = i;
i += 1;
}
return mi;
}
To find the index of the greatest value in an array, copy the original array into the new array and then sort the original array in decreasing order to get the output [22, 21, 7, 0]; now find the value 22 index in the copyNumbers array using this code copyNumbers.indexOf(numbers[0]);
<script>
const numbers = [0, 21, 22, 7];
const copyNumbers = [];
copyNumbers.push(...numbers);
numbers.sort(function(a, b){
return b - a
});
const index = copyNumbers.indexOf(numbers[0]);
console.log(index);
</script>
Make this
const max = arr.reduce((m, n) => Math.max(m, n)), then the indexes of the max
get index with findIndex
var index = arr.findIndex(i => i === max)
In order to duplicate an array in JavaScript: Which of the following is faster to use?
Slice method
var dup_array = original_array.slice();
For loop
for(var i = 0, len = original_array.length; i < len; ++i)
dup_array[i] = original_array[i];
I know both ways do only a shallow copy: if original_array contains references to objects, objects won't be cloned, but only the references will be copied, and therefore both arrays will have references to the same objects.
But this is not the point of this question.
I'm asking only about speed.
There are at least 6 (!) ways to clone an array:
loop
slice
Array.from()
concat
spread syntax (FASTEST)
map A.map(function(e){return e;});
There has been a huuuge BENCHMARKS thread, providing following information:
for blink browsers slice() is the fastest method, concat() is a bit slower, and while loop is 2.4x slower.
for other browsers while loop is the fastest method, since those browsers don't have internal optimizations for slice and concat.
This remains true in Jul 2016.
Below are simple scripts that you can copy-paste into your browser's console and run several times to see the picture. They output milliseconds, lower is better.
while loop
n = 1000*1000;
start = + new Date();
a = Array(n);
b = Array(n);
i = a.length;
while(i--) b[i] = a[i];
console.log(new Date() - start);
slice
n = 1000*1000;
start = + new Date();
a = Array(n);
b = a.slice();
console.log(new Date() - start);
Please note that these methods will clone the Array object itself, array contents however are copied by reference and are not deep cloned.
origAr == clonedArr //returns false
origAr[0] == clonedArr[0] //returns true
Technically slice is the fastest way. However, it is even faster if you add the 0 begin index.
myArray.slice(0);
is faster than
myArray.slice();
https://jsben.ch/F0SZ3
what about es6 way?
arr2 = [...arr1];
Easiest way to deep clone Array or Object:
var dup_array = JSON.parse(JSON.stringify(original_array))
🏁 Fastest Way to Clone an Array
I made this very plain utility function to test the time that it takes to clone an array. It is not 100% reliable however it can give you a bulk idea as for how long it takes to clone an existing array:
function clone(fn) {
const arr = [...Array(1000000)];
console.time('timer');
fn(arr);
console.timeEnd('timer');
}
And tested different approach:
1) 5.79ms -> clone(arr => Object.values(arr));
2) 7.23ms -> clone(arr => [].concat(arr));
3) 9.13ms -> clone(arr => arr.slice());
4) 24.04ms -> clone(arr => { const a = []; for (let val of arr) { a.push(val); } return a; });
5) 30.02ms -> clone(arr => [...arr]);
6) 39.72ms -> clone(arr => JSON.parse(JSON.stringify(arr)));
7) 99.80ms -> clone(arr => arr.map(i => i));
8) 259.29ms -> clone(arr => Object.assign([], arr));
9) Maximum call stack size exceeded -> clone(arr => Array.of(...arr));
UPDATE:
Tests were made back in 2018, so today most likely you'll get different result with current browsers.
Out of all of those, the only way to deep clone an array is by using JSON.parse(JSON.stringify(arr)).
That said, do not use the above if your array might include functions as it will return null.Thank you #GilEpshtain for this update.
var cloned_array = [].concat(target_array);
I put together a quick demo: http://jsbin.com/agugo3/edit
My results on Internet Explorer 8 are 156, 782, and 750, which would indicate slice is much faster in this case.
a.map(e => e) is another alternative for this job. As of today .map() is very fast (almost as fast as .slice(0)) in Firefox, but not in Chrome.
On the other hand, if an array is multi-dimensional, since arrays are objects and objects are reference types, none of the slice or concat methods will be a cure... So one proper way of cloning an array is an invention of Array.prototype.clone() as follows.
Array.prototype.clone = function(){
return this.map(e => Array.isArray(e) ? e.clone() : e);
};
var arr = [ 1, 2, 3, 4, [ 1, 2, [ 1, 2, 3 ], 4 , 5], 6 ],
brr = arr.clone();
brr[4][2][1] = "two";
console.log(JSON.stringify(arr));
console.log(JSON.stringify(brr));
Fastest way to clone an Array of Objects will be using spread operator
var clonedArray=[...originalArray]
or
var clonedArray = originalArray.slice(0); //with 0 index it's little bit faster than normal slice()
but the objects inside that cloned array will still pointing at the old memory location. hence change to clonedArray objects will also change the orignalArray. So
var clonedArray = originalArray.map(({...ele}) => {return ele})
this will not only create new array but also the objects will be cloned to.
disclaimer if you are working with nested object in that case spread operator will work as SHALLOW CLONE. At that point better to use
var clonedArray=JSON.parse(JSON.stringify(originalArray));
Take a look at: link. It's not about speed, but comfort. Besides as you can see you can only use slice(0) on primitive types.
To make an independent copy of an array rather than a copy of the refence to it, you can use the array slice method.
Example:
To make an independent copy of an array rather than a copy of the refence to it, you can use the array slice method.
var oldArray = ["mip", "map", "mop"];
var newArray = oldArray.slice();
To copy or clone an object :
function cloneObject(source) {
for (i in source) {
if (typeof source[i] == 'source') {
this[i] = new cloneObject(source[i]);
}
else{
this[i] = source[i];
}
}
}
var obj1= {bla:'blabla',foo:'foofoo',etc:'etc'};
var obj2= new cloneObject(obj1);
Source: link
ECMAScript 2015 way with the Spread operator:
Basic examples:
var copyOfOldArray = [...oldArray]
var twoArraysBecomeOne = [...firstArray, ..seccondArray]
Try in the browser console:
var oldArray = [1, 2, 3]
var copyOfOldArray = [...oldArray]
console.log(oldArray)
console.log(copyOfOldArray)
var firstArray = [5, 6, 7]
var seccondArray = ["a", "b", "c"]
var twoArraysBecomOne = [...firstArray, ...seccondArray]
console.log(twoArraysBecomOne);
References
6 Great Uses of the Spread Operator
Spread syntax
As #Dan said "This answer becomes outdated fast. Use benchmarks to check the actual situation", there is one specific answer from jsperf that has not had an answer for itself: while:
var i = a.length;
while(i--) { b[i] = a[i]; }
had 960,589 ops/sec with the runnerup a.concat() at 578,129 ops/sec, which is 60%.
This is the lastest Firefox (40) 64 bit.
#aleclarson created a new, more reliable benchmark.
Benchmark time!
function log(data) {
document.getElementById("log").textContent += data + "\n";
}
benchmark = (() => {
time_function = function(ms, f, num) {
var z = 0;
var t = new Date().getTime();
for (z = 0;
((new Date().getTime() - t) < ms); z++)
f(num);
return (z)
}
function clone1(arr) {
return arr.slice(0);
}
function clone2(arr) {
return [...arr]
}
function clone3(arr) {
return [].concat(arr);
}
Array.prototype.clone = function() {
return this.map(e => Array.isArray(e) ? e.clone() : e);
};
function clone4(arr) {
return arr.clone();
}
function benchmark() {
function compare(a, b) {
if (a[1] > b[1]) {
return -1;
}
if (a[1] < b[1]) {
return 1;
}
return 0;
}
funcs = [clone1, clone2, clone3, clone4];
results = [];
funcs.forEach((ff) => {
console.log("Benchmarking: " + ff.name);
var s = time_function(2500, ff, Array(1024));
results.push([ff, s]);
console.log("Score: " + s);
})
return results.sort(compare);
}
return benchmark;
})()
log("Starting benchmark...\n");
res = benchmark();
console.log("Winner: " + res[0][0].name + " !!!");
count = 1;
res.forEach((r) => {
log((count++) + ". " + r[0].name + " score: " + Math.floor(10000 * r[1] / res[0][1]) / 100 + ((count == 2) ? "% *winner*" : "% speed of winner.") + " (" + Math.round(r[1] * 100) / 100 + ")");
});
log("\nWinner code:\n");
log(res[0][0].toString());
<textarea rows="50" cols="80" style="font-size: 16; resize:none; border: none;" id="log"></textarea>
The benchmark will run for 10s since you click the button.
My results:
Chrome (V8 engine):
1. clone1 score: 100% *winner* (4110764)
2. clone3 score: 74.32% speed of winner. (3055225)
3. clone2 score: 30.75% speed of winner. (1264182)
4. clone4 score: 21.96% speed of winner. (902929)
Firefox (SpiderMonkey Engine):
1. clone1 score: 100% *winner* (8448353)
2. clone3 score: 16.44% speed of winner. (1389241)
3. clone4 score: 5.69% speed of winner. (481162)
4. clone2 score: 2.27% speed of winner. (192433)
Winner code:
function clone1(arr) {
return arr.slice(0);
}
Winner engine:
SpiderMonkey (Mozilla/Firefox)
It depends on the browser. If you look in the blog post Array.prototype.slice vs manual array creation, there is a rough guide to performance of each:
Results:
There is a much cleaner solution:
var srcArray = [1, 2, 3];
var clonedArray = srcArray.length === 1 ? [srcArray[0]] : Array.apply(this, srcArray);
The length check is required, because the Array constructor behaves differently when it is called with exactly one argument.
Remember .slice() won't work for two-dimensional arrays. You'll need a function like this:
function copy(array) {
return array.map(function(arr) {
return arr.slice();
});
}
It depends on the length of the array. If the array length is <= 1,000,000, the slice and concat methods are taking approximately the same time. But when you give a wider range, the concat method wins.
For example, try this code:
var original_array = [];
for(var i = 0; i < 10000000; i ++) {
original_array.push( Math.floor(Math.random() * 1000000 + 1));
}
function a1() {
var dup = [];
var start = Date.now();
dup = original_array.slice();
var end = Date.now();
console.log('slice method takes ' + (end - start) + ' ms');
}
function a2() {
var dup = [];
var start = Date.now();
dup = original_array.concat([]);
var end = Date.now();
console.log('concat method takes ' + (end - start) + ' ms');
}
function a3() {
var dup = [];
var start = Date.now();
for(var i = 0; i < original_array.length; i ++) {
dup.push(original_array[i]);
}
var end = Date.now();
console.log('for loop with push method takes ' + (end - start) + ' ms');
}
function a4() {
var dup = [];
var start = Date.now();
for(var i = 0; i < original_array.length; i ++) {
dup[i] = original_array[i];
}
var end = Date.now();
console.log('for loop with = method takes ' + (end - start) + ' ms');
}
function a5() {
var dup = new Array(original_array.length)
var start = Date.now();
for(var i = 0; i < original_array.length; i ++) {
dup.push(original_array[i]);
}
var end = Date.now();
console.log('for loop with = method and array constructor takes ' + (end - start) + ' ms');
}
a1();
a2();
a3();
a4();
a5();
If you set the length of original_array to 1,000,000, the slice method and concat method are taking approximately the same time (3-4 ms, depending on the random numbers).
If you set the length of original_array to 10,000,000, then the slice method takes over 60 ms and the concat method takes over 20 ms.
In ES6, you can simply utilize the Spread syntax.
Example:
let arr = ['a', 'b', 'c'];
let arr2 = [...arr];
Please note that the spread operator generates a completely new array, so modifying one won't affect the other.
Example:
arr2.push('d') // becomes ['a', 'b', 'c', 'd']
console.log(arr) // while arr retains its values ['a', 'b', 'c']
A simple solution:
original = [1,2,3]
cloned = original.map(x=>x)
const arr = ['1', '2', '3'];
// Old way
const cloneArr = arr.slice();
// ES6 way
const cloneArrES6 = [...arr];
// But problem with 3rd approach is that if you are using muti-dimensional
// array, then only first level is copied
const nums = [
[1, 2],
[10],
];
const cloneNums = [...nums];
// Let's change the first item in the first nested item in our cloned array.
cloneNums[0][0] = '8';
console.log(cloneNums);
// [ [ '8', 2 ], [ 10 ], [ 300 ] ]
// NOOooo, the original is also affected
console.log(nums);
// [ [ '8', 2 ], [ 10 ], [ 300 ] ]
So, in order to avoid these scenarios to happen, use
const arr = ['1', '2', '3'];
const cloneArr = Array.from(arr);
There were several ways to clone an array. Basically, Cloning was categorized in two ways:
Shallow copy
Deep copy
Shallow copies only cover the 1st level of the array and the rest are
referenced. If you want a true copy of nested elements in the arrays, you’ll need a
deep clone.
Example :
const arr1 = [1,2,3,4,5,6,7]
// Normal Array (shallow copy is enough)
const arr2 = [1,2,3,[4],[[5]],6,7]
// Nested Array (Deep copy required)
Approach 1 : Using (...)Spread Operator (Shallow copy enough)
const newArray = [...arr1] // [1,2,3,4,5,6,7]
Approach 2 : Using Array builtIn Slice method (Deep copy)
const newArray = arr1.slice() // [1,2,3,4,5,6,7]
Approach 3 : Using Array builtIn Concat method (Deep a copy)
const newArray = [].concat(arr1) // [1,2,3,4,5,6,7]
Approach 4 : Using JSON.stringify/parse. (Deep a copy & fastest)
const newArray = JSON.parse(JSON.stringify(arr2));) // [1,2,3,[4],[[5]],6,7]
Approach 5: Using own recursive function or using loadash's __.cloneDeep method. (Deep copy)
Fast ways to duplicate an array in JavaScript in Order:
#1: array1copy = [...array1];
#2: array1copy = array1.slice(0);
#3: array1copy = array1.slice();
If your array objects contain some JSON-non-serializable content (functions, Number.POSITIVE_INFINITY, etc.) better to use
array1copy = JSON.parse(JSON.stringify(array1))
You can follow this code. Immutable way array clone. This is the perfect way to array cloning
const array = [1, 2, 3, 4]
const newArray = [...array]
newArray.push(6)
console.log(array)
console.log(newArray)
If you want a REAL cloned object/array in JS with cloned references of all attributes and sub-objects:
export function clone(arr) {
return JSON.parse(JSON.stringify(arr))
}
ALL other operations do not create clones, because they just change the base address of the root element, not of the included objects.
Except you traverse recursive through the object-tree.
For a simple copy, these are OK. For storage address relevant operations I suggest (and in most all other cases, because this is fast!) to type convert into string and back in a complete new object.
If you are taking about slice it is used to copy elements from an array and create a clone with same no. of elements or less no. of elements.
var arr = [1, 2, 3 , 4, 5];
function slc() {
var sliced = arr.slice(0, 5);
// arr.slice(position to start copying master array , no. of items in new array)
console.log(sliced);
}
slc(arr);