Related
I have tried to this answer to find all permutations of size K=6 of an array of strings, but the array I'm permuting is way too large (~13,000 elements but I can guarantee most of those will be duplicates), which means I'm getting:
....
re-permuting with 6925/12972
node:internal/console/constructor:257
value: function(streamSymbol, string) {
^
RangeError: Maximum call stack size exceeded
at console.value (node:internal/console/constructor:257:20)
at console.log (node:internal/console/constructor:359:26)
at permute (/home/path/to/code/permutation.js:22:17)
at permute (/home/path/to/code/permutation.js:23:9)
.....
re-permuting with 6924/12972
....
re-permuting with 6918/12972
And then it dies. I guessed that is the recursion that's the problem.
I know that there's at most ~300 unique elements in my input (which is how I know that many of the array elements must be duplicates), but I don't know if that's 10,000 instances of one element, and then the rest are individually unique elements or at least K of each unique element. Because of that I can't just fed them into a Set, and there maybe fewer than K of one element so I can't just create a new input by duplicating the new ones K times.
Here is my slightly modified (for readability and logging only) version of the code from the above linked answer (on second look, this algorithm is far from optimal):
let permArr = [];
let usedChars = [];
let originalLength;
/**
* Subsets of permutations of an array
* #param {any[]} input array of elements to permute
* #param {number} subsetLength size of the subsets to return
* #returns {Array[]} and array of arrays
*/
function permute(input, subsetLength = input.length) {
let index
let ch;
originalLength ??= input.length;
for (index = 0; index < input.length; index++) {
ch = input.splice(index, 1)[0];
usedChars.push(ch);
if (input.length == 0) {
let toAdd = usedChars.slice(0, subsetLength);
// resizing the returned array to size k
if (!permArr.includes(toAdd)) permArr.push(toAdd);
}
console.log(`re-permuting with ${input.length}/${originalLength}`)
permute(input, subsetLength);
input.splice(index, 0, ch);
usedChars.pop();
}
return permArr
};
And I found this answer but I do not follow it at all, and this other answer is similar but still uses recursion.
How can I make this without recursion/more performant so it can handle much larger arrays? I'm using NodeJs, and I'm not averse to using different data types.
I don't know if that's 10,000 instances of one element, and then the rest are individually unique elements or at least K of each unique element. Because of that I can't just fed them into a Set, and there maybe fewer than K of one element so I can't just create a new input by duplicating the new ones K times
So just group and count them. Seems simple enough:
function subsetPermutations(arr, size) {
const counts = {};
for (const el of arr) {
counts[el] = (counts[el] ?? 0) + 1;
}
const unique = Object.keys(counts);
const result = Array.from({length: size});
function* recurse(depth) {
if (depth == size) {
yield result;
} else {
for (const el of unique) {
if (counts[el]) {
result[depth] = el;
counts[el]--;
yield* recurse(depth+1)
counts[el]++;
}
}
}
}
return recurse(0);
}
for (const perm of subsetPermutations(["a", "b", "b", "c", "c", "c"], 3)) {
console.log(perm.join('-'));
}
I have tried to this answer to find all permutations of size K=6, but the array I'm permuting is way too large (~13,000 elements), however I can guarantee I know that there's at most ~300 unique
That's still roughtly 3006 permutations, which is far too many to put them into an array. The function above is designed as an iterator so that you can work on the current result in a loop before it gets mutated in the next iteration, to avoid any allocation overhead, but it still will take too long to generate all of them.
How can I make this without recursion/more performant so it can handle much larger arrays? I'm using NodeJs, and I'm not averse to using different data types.
You can use a Map instead of the object for counts, but I doubt it'll be much faster for just 300 different elements.
Avoiding recursion is unnecessary since it only goes 6 level deep, there won't be a stack overflow unlike with your inefficient solution. But for performance, you might still try this approach of dynamically generating nested loops.
I'm having a tough time figuring out how to loop through an array and if certain items do exist within the array, i'd like to perform a .slice(0, 16) to kind of filter an already existing array (lets call that existing array "routes").
For example, a previous process will yield the following array:
points = ['=00ECY20WA200_RECV_P1SEL',
'=00ECY20WA200_RECV_P2SEL',
'=00RECV_C1A_EINCSCMPP1',
'=00RECV_C1A_EINCSCMPP2',
'=00BYPS_C1A_EINCSCMP',
'=00ECY20WA200_BYPS_SPSL1',
'=00ECC92AG184YB01',
'=00ECC92AG185YB01',
'=00ECC92AG186YB01',
'=00ECC92AG187YB01',
]
So if any of the above items exist in the "points" Array, which in this case they all do (but in some cases it could just be 1 of the 10 items existing there), I'm trying to perform routes.slice(0, 16) to the other already existing array.
I've tried lots of different ways (for loops with if statements) and at this point I'm not sure if its my syntax or what, but I'm back at square 0 and I don't even have a competent piece of code to show for. Any direction would be greatly appreciated.
You could use a hash table for checking and filtering.
var points = ['=00ECY20WA200_RECV_P1SEL', '=00ECY20WA200_RECV_P2SEL', '=00RECV_C1A_EINCSCMPP1', '=00RECV_C1A_EINCSCMPP2', '=00BYPS_C1A_EINCSCMP', '=00ECY20WA200_BYPS_SPSL1', '=00ECC92AG184YB01', '=00ECC92AG185YB01', '=00ECC92AG186YB01', '=00ECC92AG187YB01'],
hash = Object.create(null),
filtered = points.filter(function (a) {
if (!hash[a.slice(0, 16)]) {
hash[a.slice(0, 16)] = true;
return true;
}
});
console.log(filtered);
ES6 with Set
var points = ['=00ECY20WA200_RECV_P1SEL', '=00ECY20WA200_RECV_P2SEL', '=00RECV_C1A_EINCSCMPP1', '=00RECV_C1A_EINCSCMPP2', '=00BYPS_C1A_EINCSCMP', '=00ECY20WA200_BYPS_SPSL1', '=00ECC92AG184YB01', '=00ECC92AG185YB01', '=00ECC92AG186YB01', '=00ECC92AG187YB01'],
pSet = new Set,
filtered = points.filter(a => !pSet.has(a.slice(0, 16)) && pSet.add(a.slice(0, 16)));
console.log(filtered);
EDIT: So it seems like you want to remove an element from an array called routes for each element in the points array. This is how you could do this:
function removeBrokenRoutes(brokenPoints, routes){
for(let pt of brokenPoints){
let index = routes.indexOf(pt);
if(index !== -1) routes.splice(index,1);
}
return routes;
}
Keep in mind that the larger the arrays, the more time this is going to take to complete.
You could use the filter and indexOf methods in combination:
var arr = [/* all the data you're checking against */];
var points = [/* the data you're checking for */];
var filteredArr = arr.filter(function(x) {
// will return -1 if the point is not found
return points.indexOf(x) !== -1;
});
filteredArr will contain all the points that appear in both arrays. The filter function works by taking a function with one argument x, which represents each item in the array. if the function returns true, the item will be added to the new array (filteredArr), and if false the function will move on to the next item. indexOf will check if the item is found in the other array. Also it is important to note that you will need a more complex solution (such as a hashtable) if the data set is very, very large as this is not necessarily the most performant method. But it's a good place to start as it is easy to understand.
I am looking for an algorithm to merge multiple sorted sequences, lets say X sorted sequences with n elements, into one sorted sequence in javascript , can you provide some examples?
note: I do not want to use any library.
Trying to solve https://icpc.kattis.com/problems/stacking
what will be the minimal number of operations needed to merge sorted arrays, under conditions :
Split: a single stack can be split into two stacks by lifting any top portion of the stack and putting it aside to form a new stack.
Join: two stacks can be joined by putting one on top of the other. This is allowed only if the bottom plate of the top stack is no larger than the top plate of the bottom stack, that is, the joined stack has to be properly ordered.
History
This problem has been solved for more than a century, going back to Hermann Hollerith and punchcards. Huge sets of punchcards, such as those resulting from a census, were sorted by dividing them into batches, sorting each batch, and then merging the sorted batches--the so-called
"merge sort". Those tape drives you see spinning in 1950's sci-fi movies were most likely merging multiple sorted tapes onto one.
Algorithm
All the algorithms you need can be found at https://en.wikipedia.org/wiki/Merge_algorithm. Writing this in JS is straightforward. More information is available in the question Algorithm for N-way merge. See also this question, which is an almost exact duplicate, although I'm not sure any of the answers are very good.
The naive concat-and-resort approach does not even qualify as an answer to the problem. The somewhat naive take-the-next-minimum-value-from-any-input approach is much better, but not optimal, because it takes more time than necessary to find the next input to take a value from. That is why the best solution using something called a "min-heap" or a "priority queue".
Simple JS solution
Here's a real simple version, which I make no claim to be optimized, other than in the sense of being able to see what it is doing:
const data = [[1, 3, 5], [2, 4]];
// Merge an array or pre-sorted arrays, based on the given sort criteria.
function merge(arrays, sortFunc) {
let result = [], next;
// Add an 'index' property to each array to keep track of where we are in it.
arrays.forEach(array => array.index = 0);
// Find the next array to pull from.
// Just sort the list of arrays by their current value and take the first one.
function findNext() {
return arrays.filter(array => array.index < array.length)
.sort((a, b) => sortFunc(a[a.index], b[b.index]))[0];
}
// This is the heart of the algorithm.
while (next = findNext()) result.push(next[next.index++]);
return result;
}
function arithAscending(a, b) { return a - b; }
console.log(merge(data, arithAscending));
The above code maintains an index property on each input array to remember where we are. The simplistic alternative would be to shift the element from the front of each array when it is its turn to be merged, but that would be rather inefficient.
Optimizing finding the next array to pull from
This naive implementation of findNext, to find the array to pull the next value from, simply sorts the list of inputs by the first element, and takes the first array in the result. You can optimize this by using a "min-heap" to manage the arrays in sorted order, which removes the need to resort them each time. A min-heap is a tree, consisting of nodes, where each node contains a value which is the minimum of all values below, with left and right nodes giving additional (greater) values, and so on. You can find information on a JS implementation of a min-heap here.
A generator solution
It might be slightly cleaner to write this as a generator which takes a list of iterables as inputs, which includes arrays.
// Test data.
const data = [[1, 3, 5], [2, 4]];
// Merge an array or pre-sorted arrays, based on the given sort criteria.
function* merge(iterables, sortFunc) {
let next;
// Create iterators, with "result" property to hold most recent result.
const iterators = iterables.map(iterable => {
const iterator = iterable[Symbol.iterator]();
iterator.result = iterator.next();
return iterator;
});
// Find the next iterator whose value to use.
function findNext() {
return iterators
.filter(iterator => !iterator.result.done)
.reduce((ret, cur) => !ret || cur.result.value < ret.result.value ? cur : ret,
null);
}
// This is the heart of the algorithm.
while (next = findNext()) {
yield next.result.value;
next.result = next.next();
}
}
function arithAscending(a, b) { return a - b; }
console.log(Array.from(merge(data, arithAscending)));
The naive approach is concatenating all the k sequences, and sort the result. But if each sequence has n elements, the the cost will be O(k*n*log(k*n)). Too much!
Instead, you can use a priority queue or heap. Like this:
var sorted = [];
var pq = new MinPriorityQueue(function(a, b) {
return a.number < b.number;
});
var indices = new Array(k).fill(0);
for (var i=0; i<k; ++i) if (sequences[i].length > 0) {
pq.insert({number: sequences[i][0], sequence: i});
}
while (!pq.empty()) {
var min = pq.findAndDeleteMin();
sorted.push(min.number);
++indices[min.sequence];
if (indices[min.sequence] < sequences[i].length) pq.insert({
number: sequences[i][indices[min.sequence]],
sequence: min.sequence
});
}
The priority queue only contains at most k elements simultaneously, one for each sequence. You keep extracting the minimum one, and inserting the following element in that sequence.
With this, the cost will be:
k*n insertions to a heap of k elements: O(k*n)
k*n deletions in a heap of k elements: O(k*n*log(k))
Various constant operations for each number: O(k*n)
So only O(k*n*log(k))
Just add them into one big array and sort it.
You could use a heap, add the first element of each sequence to it, pop the lowest one (that's your first merged element), add the next element from the sequence of the popped element and continue until all sequences are over.
It's much easier to just add them into one big array and sort it, though.
This is a simple javascript algo I came up with. Hope it helps. It will take any number of sorted arrays and do a merge. I am maintaining an array for index of positions of the arrays. It basically iterates through the index positions of each array and checks which one is the minimum. Based on that it picks up the min and inserts into the merged array. Thereafter it increments the position index for that particular array. I feel the time complexity can be improved. Will post back if I come up with a better algo, possibly using a min heap.
function merge() {
var mergedArr = [],pos = [], finished = 0;
for(var i=0; i<arguments.length; i++) {
pos[i] = 0;
}
while(finished != arguments.length) {
var min = null, selected;
for(var i=0; i<arguments.length; i++) {
if(pos[i] != arguments[i].length) {
if(min == null || min > arguments[i][pos[i]]) {
min = arguments[i][pos[i]];
selected = i;
}
}
}
mergedArr.push(arguments[selected][pos[selected]]);
pos[selected]++;
if(pos[selected] == arguments[selected].length) {
finished++;
}
}
return mergedArr;
}
This is a beautiful question. Unlike concatenating the arrays and applying a .sort(); a simple dynamical programming approach with .reduce() would yield a result in O(m.n) time complexity. Where m is the number of arrays and n is their average length.
We will handle the arrays one by one. First we will merge the first two arrays and then we will merge the result with the third array and so on.
function mergeSortedArrays(a){
return a.reduce(function(p,c){
var pc = 0,
cc = 0,
len = p.length < c.length ? p.length : c.length,
res = [];
while (p[pc] !== undefined && c[cc] !== undefined) p[pc] < c[cc] ? res.push(p[pc++])
: res.push(c[cc++]);
return p[pc] === undefined ? res.concat(c.slice(cc))
: res.concat(p.slice(pc));
});
}
var sortedArrays = Array(5).fill().map(_ => Array(~~(Math.random()*5)+5).fill().map(_ => ~~(Math.random()*20)).sort((a,b) => a-b));
sortedComposite = mergeSortedArrays(sortedArrays);
sortedArrays.forEach(a => console.log(JSON.stringify(a)));
console.log(JSON.stringify(sortedComposite));
OK as per #Mirko Vukušić's comparison of this algorithm with .concat() and .sort(), this algorithm is still the fastest solution with FF but not with Chrome. The Chrome .sort() is actually very fast and i can not make sure about it's time complexity. I just needed to tune it up a little for JS performance without touching the essence of the algorithm at all. So now it seems to be faster than FF's concat and sort.
function mergeSortedArrays(a){
return a.reduce(function(p,c){
var pc = 0,
pl =p.length,
cc = 0,
cl = c.length,
res = [];
while (pc < pl && cc < cl) p[pc] < c[cc] ? res.push(p[pc++])
: res.push(c[cc++]);
if (cc < cl) while (cc < cl) res.push(c[cc++]);
else while (pc < pl) res.push(p[pc++]);
return res;
});
}
function concatAndSort(a){
return a.reduce((p,c) => p.concat(c))
.sort((a,b) => a-b);
}
var sortedArrays = Array(5000).fill().map(_ => Array(~~(Math.random()*5)+5).fill().map(_ => ~~(Math.random()*20)).sort((a,b) => a-b));
console.time("merge");
mergeSorted = mergeSortedArrays(sortedArrays);
console.timeEnd("merge");
console.time("concat");
concatSorted = concatAndSort(sortedArrays);
console.timeEnd("concat");
5000 random sorted arrays of random lengths between 5-10.
es6 syntax:
function mergeAndSort(arrays) {
return [].concat(...arrays).sort()
}
function receives array of arrays to merge and sort.
*EDIT: as cought by #Redu, above code is incorrect. Default sort() if sorting function is not provided, is string Unicode. Fixed (and slower) code is:
function mergeAndSort(arrays) {
return [].concat(...arrays).sort((a,b)=>a-b)
}
This question's answers are a community effort. Edit existing answers to improve this post. It is not currently accepting new answers or interactions.
Is there a way to empty an array and if so possibly with .remove()?
For instance,
A = [1,2,3,4];
How can I empty that?
Ways to clear an existing array A:
Method 1
(this was my original answer to the question)
A = [];
This code will set the variable A to a new empty array. This is perfect if you don't have references to the original array A anywhere else because this actually creates a brand new (empty) array. You should be careful with this method because if you have referenced this array from another variable or property, the original array will remain unchanged. Only use this if you only reference the array by its original variable A.
This is also the fastest solution.
This code sample shows the issue you can encounter when using this method:
var arr1 = ['a','b','c','d','e','f'];
var arr2 = arr1; // Reference arr1 by another variable
arr1 = [];
console.log(arr2); // Output ['a','b','c','d','e','f']
Method 2 (as suggested by Matthew Crumley)
A.length = 0
This will clear the existing array by setting its length to 0. It also works when using "strict mode" in ECMAScript 5 because the length property of an array is a read/write property.
Method 3 (as suggested by Anthony)
A.splice(0,A.length)
Using .splice() will work perfectly, but since the .splice() function will return an array with all the removed items, it will actually return a copy of the original array. Benchmarks suggest that this has no effect on performance whatsoever.
Method 4 (as suggested by tanguy_k)
while(A.length > 0) {
A.pop();
}
This solution is not very succinct, and it is also the slowest solution, contrary to earlier benchmarks referenced in the original answer.
Performance
Of all the methods of clearing an existing array, methods 2 and 3 are very similar in performance and are a lot faster than method 4. See this benchmark.
As pointed out by Diadistis in their answer below, the original benchmarks that were used to determine the performance of the four methods described above were flawed. The original benchmark reused the cleared array so the second iteration was clearing an array that was already empty.
The following benchmark fixes this flaw: http://jsben.ch/#/hyj65. It clearly shows that methods #2 (length property) and #3 (splice) are the fastest (not counting method #1 which doesn't change the original array).
This has been a hot topic and the cause of a lot of controversy. There are actually many correct answers and because this answer has been marked as the accepted answer for a very long time, I will include all of the methods here.
If you need to keep the original array because you have other references to it that should be updated too, you can clear it without creating a new array by setting its length to zero:
A.length = 0;
Here the fastest working implementation while keeping the same array ("mutable"):
function clearArray(array) {
while (array.length > 0) {
array.pop();
}
}
FYI it cannot be simplified to while (array.pop()): the tests will fail.
FYI Map and Set define clear(), it would have seem logical to have clear() for Array too.
TypeScript version:
function clearArray<T>(array: T[]) {
while (array.length > 0) {
array.pop();
}
}
The corresponding tests:
describe('clearArray()', () => {
test('clear regular array', () => {
const array = [1, 2, 3, 4, 5];
clearArray(array);
expect(array.length).toEqual(0);
expect(array[0]).toEqual(undefined);
expect(array[4]).toEqual(undefined);
});
test('clear array that contains undefined and null', () => {
const array = [1, undefined, 3, null, 5];
clearArray(array);
expect(array.length).toEqual(0);
expect(array[0]).toEqual(undefined);
expect(array[4]).toEqual(undefined);
});
});
Here the updated jsPerf: http://jsperf.com/array-destroy/32 http://jsperf.com/array-destroy/152
jsPerf offline. Similar benchmark: https://jsben.ch/hyj65
A more cross-browser friendly and more optimal solution will be to use the splice method to empty the content of the array A as below:
A.splice(0, A.length);
The answers that have no less that 2739 upvotes by now are misleading and incorrect.
The question is: "How do you empty your existing array?" E.g. for A = [1,2,3,4].
Saying "A = [] is the answer" is ignorant and absolutely incorrect. [] == [] is false.
This is because these two arrays are two separate, individual objects, with their own two identities, taking up their own space in the digital world, each on its own.
Let's say your mother asks you to empty the trash can.
You don't bring in a new one as if you've done what you've been asked for.
Instead, you empty the trash can.
You don't replace the filled one with a new empty can, and you don't take the label "A" from the filled can and stick it to the new one as in A = [1,2,3,4]; A = [];
Emptying an array object is the easiest thing ever:
A.length = 0;
This way, the can under "A" is not only empty, but also as clean as new!
Furthermore, you are not required to remove the trash by hand until the can is empty! You were asked to empty the existing one, completely, in one turn, not to pick up the trash until the can gets empty, as in:
while(A.length > 0) {
A.pop();
}
Nor, to put your left hand at the bottom of the trash, holding it with your right at the top to be able to pull its content out as in:
A.splice(0, A.length);
No, you were asked to empty it:
A.length = 0;
This is the only code that correctly empties the contents of a given JavaScript array.
Performance test:
http://jsperf.com/array-clear-methods/3
a = []; // 37% slower
a.length = 0; // 89% slower
a.splice(0, a.length) // 97% slower
while (a.length > 0) {
a.pop();
} // Fastest
You can add this to your JavaScript file to allow your arrays to be "cleared":
Array.prototype.clear = function() {
this.splice(0, this.length);
};
Then you can use it like this:
var list = [1, 2, 3];
list.clear();
Or if you want to be sure you don't destroy something:
if (!Array.prototype.clear) {
Array.prototype.clear = function() {
this.splice(0, this.length);
};
}
Lots of people think you shouldn't modify native objects (like Array), and I'm inclined to agree. Please use caution in deciding how to handle this.
You can easily create a function to do that for you, change the length or even add it to native Array as remove() function for reuse.
Imagine you have this array:
var arr = [1, 2, 3, 4, 5]; //the array
OK, just simply run this:
arr.length = 0; //change the length
and the result is:
[] //result
easy way to empty an array...
Also using loop which is not necessary but just another way to do that:
/* could be arr.pop() or arr.splice(0)
don't need to return as main array get changed */
function remove(arr) {
while(arr.length) {
arr.shift();
}
}
There are also tricky way which you can think about, for example something like this:
arr.splice(0, arr.length); //[]
So if arr has 5 items, it will splice 5 items from 0, which means nothing will remain in the array.
Also other ways like simply reassign the array for example:
arr = []; //[]
If you look at the Array functions, there are many other ways to do this, but the most recommended one could be changing the length.
As I said in the first place, you can also prototype remove() as it's the answer to your question. you can simply choose one of the methods above and prototype it to Array object in JavaScript, something like:
Array.prototype.remove = Array.prototype.remove || function() {
this.splice(0, this.length);
};
and you can simply call it like this to empty any array in your javascript application:
arr.remove(); //[]
If you are using
a = [];
Then you are assigning new array reference to a, if reference in a is already assigned to any other variable, then it will not empty that array too and hence garbage collector will not collect that memory.
For ex.
var a=[1,2,3];
var b=a;
a=[];
console.log(b);// It will print [1,2,3];
or
a.length = 0;
When we specify a.length, we are just resetting boundaries of the array and memory for rest array elements will be connected by garbage collector.
Instead of these two solutions are better.
a.splice(0,a.length)
and
while(a.length > 0) {
a.pop();
}
As per previous answer by kenshou.html, second method is faster.
There is a lot of confusion and misinformation regarding the while;pop/shift performance both in answers and comments. The while/pop solution has (as expected) the worst performance. What's actually happening is that setup runs only once for each sample that runs the snippet in a loop. eg:
var arr = [];
for (var i = 0; i < 100; i++) {
arr.push(Math.random());
}
for (var j = 0; j < 1000; j++) {
while (arr.length > 0) {
arr.pop(); // this executes 100 times, not 100000
}
}
I have created a new test that works correctly :
http://jsperf.com/empty-javascript-array-redux
Warning: even in this version of the test you can't actually see the real difference because cloning the array takes up most of the test time. It still shows that splice is the fastest way to clear the array (not taking [] into consideration because while it is the fastest it's not actually clearing the existing array).
Array.prototype.clear = function() {
this.length = 0;
};
And call it: array.clear();
In case you are interested in the memory allocation, you may compare each approach using something like this jsfiddle in conjunction with chrome dev tools' timeline tab. You will want to use the trash bin icon at the bottom to force a garbage collection after 'clearing' the array. This should give you a more definite answer for the browser of your choice. A lot of answers here are old and I wouldn't rely on them but rather test as in #tanguy_k's answer above.
(for an intro to the aforementioned tab you can check out here)
Stackoverflow forces me to copy the jsfiddle so here it is:
<html>
<script>
var size = 1000*100
window.onload = function() {
document.getElementById("quantifier").value = size
}
function scaffold()
{
console.log("processing Scaffold...");
a = new Array
}
function start()
{
size = document.getElementById("quantifier").value
console.log("Starting... quantifier is " + size);
console.log("starting test")
for (i=0; i<size; i++){
a[i]="something"
}
console.log("done...")
}
function tearDown()
{
console.log("processing teardown");
a.length=0
}
</script>
<body>
<span style="color:green;">Quantifier:</span>
<input id="quantifier" style="color:green;" type="text"></input>
<button onclick="scaffold()">Scaffold</button>
<button onclick="start()">Start</button>
<button onclick="tearDown()">Clean</button>
<br/>
</body>
</html>
And you should take note that it may depend on the type of the array elements, as javascript manages strings differently than other primitive types, not to mention arrays of objects. The type may affect what happens.
Use a modified version of Jan's initial suggestion:
var originalLength = A.length;
for (var i = originalLength; i > 0; i--) {
A.pop();
}
Terser:
for (let i = A.length; i > 0;A.pop(),i--) {}
Or here's another take:
while(!A[Symbol.iterator]().next().done)A.shift()
A.splice(0);
I just did this on some code I am working on. It cleared the array.
If you use constants then you have no choice:
const numbers = [1, 2, 3]
You can not reasign:
numbers = []
You can only truncate:
numbers.length = 0
To Empty a Current memory location of an array use: 'myArray.length = 0' or 'myArray.pop() UN-till its length is 0'
length : You can set the length property to truncate an array at any time. When you extend an array by changing its length property, the number of actual elements increases.
pop() : The pop method removes the last element from an array and returns that returns the removed value.
shift() : The shift method removes the element at the zeroeth index and shifts the values at consecutive indexes down, then returns the removed value.
Example:
var arr = ['77'];
arr.length = 20;
console.log("Increasing : ", arr); // (20) ["77", empty × 19]
arr.length = 12;
console.log("Truncating : ", arr); // (12) ["77", empty × 11]
var mainArr = new Array();
mainArr = ['1', '2', '3', '4'];
var refArr = mainArr;
console.log('Current', mainArr, 'Refered', refArr);
refArr.length = 3;
console.log('Length: ~ Current', mainArr, 'Refered', refArr);
mainArr.push('0');
console.log('Push to the End of Current Array Memory Location \n~ Current', mainArr, 'Refered', refArr);
mainArr.poptill_length(0);
console.log('Empty Array \n~ Current', mainArr, 'Refered', refArr);
Array.prototype.poptill_length = function (e) {
while (this.length) {
if( this.length == e ) break;
console.log('removed last element:', this.pop());
}
};
new Array() | [] Create an Array with new memory location by using Array constructor or array literal.
mainArr = []; // a new empty array is addressed to mainArr.
var arr = new Array('10'); // Array constructor
arr.unshift('1'); // add to the front
arr.push('15'); // add to the end
console.log("After Adding : ", arr); // ["1", "10", "15"]
arr.pop(); // remove from the end
arr.shift(); // remove from the front
console.log("After Removing : ", arr); // ["10"]
var arrLit = ['14', '17'];
console.log("array literal « ", indexedItem( arrLit ) ); // {0,14}{1,17}
function indexedItem( arr ) {
var indexedStr = "";
arr.forEach(function(item, index, array) {
indexedStr += "{"+index+","+item+"}";
console.log(item, index);
});
return indexedStr;
}
slice() : By using slice function we get an shallow copy of elements from the original array, with new memory address, So that any modification on cloneArr will not affect to an actual|original array.
var shallowCopy = mainArr.slice(); // this is how to make a copy
var cloneArr = mainArr.slice(0, 3);
console.log('Main', mainArr, '\tCloned', cloneArr);
cloneArr.length = 0; // Clears current memory location of an array.
console.log('Main', mainArr, '\tCloned', cloneArr);
I'm surprised no one has suggested this yet:
let xs = [1,2,3,4];
for (let i in xs)
delete xs[i];
This yields an array in quite a different state from the other solutions. In a sense, the array has been 'emptied':
xs
=> Array [ <4 empty slots> ]
[...xs]
=> Array [ undefined, undefined, undefined, undefined ]
xs.length
=> 4
xs[0]
=> ReferenceError: reference to undefined property xs[0]
You can produce an equivalent array with [,,,,] or Array(4)
This question's answers are a community effort. Edit existing answers to improve this post. It is not currently accepting new answers or interactions.
Is there a way to empty an array and if so possibly with .remove()?
For instance,
A = [1,2,3,4];
How can I empty that?
Ways to clear an existing array A:
Method 1
(this was my original answer to the question)
A = [];
This code will set the variable A to a new empty array. This is perfect if you don't have references to the original array A anywhere else because this actually creates a brand new (empty) array. You should be careful with this method because if you have referenced this array from another variable or property, the original array will remain unchanged. Only use this if you only reference the array by its original variable A.
This is also the fastest solution.
This code sample shows the issue you can encounter when using this method:
var arr1 = ['a','b','c','d','e','f'];
var arr2 = arr1; // Reference arr1 by another variable
arr1 = [];
console.log(arr2); // Output ['a','b','c','d','e','f']
Method 2 (as suggested by Matthew Crumley)
A.length = 0
This will clear the existing array by setting its length to 0. It also works when using "strict mode" in ECMAScript 5 because the length property of an array is a read/write property.
Method 3 (as suggested by Anthony)
A.splice(0,A.length)
Using .splice() will work perfectly, but since the .splice() function will return an array with all the removed items, it will actually return a copy of the original array. Benchmarks suggest that this has no effect on performance whatsoever.
Method 4 (as suggested by tanguy_k)
while(A.length > 0) {
A.pop();
}
This solution is not very succinct, and it is also the slowest solution, contrary to earlier benchmarks referenced in the original answer.
Performance
Of all the methods of clearing an existing array, methods 2 and 3 are very similar in performance and are a lot faster than method 4. See this benchmark.
As pointed out by Diadistis in their answer below, the original benchmarks that were used to determine the performance of the four methods described above were flawed. The original benchmark reused the cleared array so the second iteration was clearing an array that was already empty.
The following benchmark fixes this flaw: http://jsben.ch/#/hyj65. It clearly shows that methods #2 (length property) and #3 (splice) are the fastest (not counting method #1 which doesn't change the original array).
This has been a hot topic and the cause of a lot of controversy. There are actually many correct answers and because this answer has been marked as the accepted answer for a very long time, I will include all of the methods here.
If you need to keep the original array because you have other references to it that should be updated too, you can clear it without creating a new array by setting its length to zero:
A.length = 0;
Here the fastest working implementation while keeping the same array ("mutable"):
function clearArray(array) {
while (array.length > 0) {
array.pop();
}
}
FYI it cannot be simplified to while (array.pop()): the tests will fail.
FYI Map and Set define clear(), it would have seem logical to have clear() for Array too.
TypeScript version:
function clearArray<T>(array: T[]) {
while (array.length > 0) {
array.pop();
}
}
The corresponding tests:
describe('clearArray()', () => {
test('clear regular array', () => {
const array = [1, 2, 3, 4, 5];
clearArray(array);
expect(array.length).toEqual(0);
expect(array[0]).toEqual(undefined);
expect(array[4]).toEqual(undefined);
});
test('clear array that contains undefined and null', () => {
const array = [1, undefined, 3, null, 5];
clearArray(array);
expect(array.length).toEqual(0);
expect(array[0]).toEqual(undefined);
expect(array[4]).toEqual(undefined);
});
});
Here the updated jsPerf: http://jsperf.com/array-destroy/32 http://jsperf.com/array-destroy/152
jsPerf offline. Similar benchmark: https://jsben.ch/hyj65
A more cross-browser friendly and more optimal solution will be to use the splice method to empty the content of the array A as below:
A.splice(0, A.length);
The answers that have no less that 2739 upvotes by now are misleading and incorrect.
The question is: "How do you empty your existing array?" E.g. for A = [1,2,3,4].
Saying "A = [] is the answer" is ignorant and absolutely incorrect. [] == [] is false.
This is because these two arrays are two separate, individual objects, with their own two identities, taking up their own space in the digital world, each on its own.
Let's say your mother asks you to empty the trash can.
You don't bring in a new one as if you've done what you've been asked for.
Instead, you empty the trash can.
You don't replace the filled one with a new empty can, and you don't take the label "A" from the filled can and stick it to the new one as in A = [1,2,3,4]; A = [];
Emptying an array object is the easiest thing ever:
A.length = 0;
This way, the can under "A" is not only empty, but also as clean as new!
Furthermore, you are not required to remove the trash by hand until the can is empty! You were asked to empty the existing one, completely, in one turn, not to pick up the trash until the can gets empty, as in:
while(A.length > 0) {
A.pop();
}
Nor, to put your left hand at the bottom of the trash, holding it with your right at the top to be able to pull its content out as in:
A.splice(0, A.length);
No, you were asked to empty it:
A.length = 0;
This is the only code that correctly empties the contents of a given JavaScript array.
Performance test:
http://jsperf.com/array-clear-methods/3
a = []; // 37% slower
a.length = 0; // 89% slower
a.splice(0, a.length) // 97% slower
while (a.length > 0) {
a.pop();
} // Fastest
You can add this to your JavaScript file to allow your arrays to be "cleared":
Array.prototype.clear = function() {
this.splice(0, this.length);
};
Then you can use it like this:
var list = [1, 2, 3];
list.clear();
Or if you want to be sure you don't destroy something:
if (!Array.prototype.clear) {
Array.prototype.clear = function() {
this.splice(0, this.length);
};
}
Lots of people think you shouldn't modify native objects (like Array), and I'm inclined to agree. Please use caution in deciding how to handle this.
You can easily create a function to do that for you, change the length or even add it to native Array as remove() function for reuse.
Imagine you have this array:
var arr = [1, 2, 3, 4, 5]; //the array
OK, just simply run this:
arr.length = 0; //change the length
and the result is:
[] //result
easy way to empty an array...
Also using loop which is not necessary but just another way to do that:
/* could be arr.pop() or arr.splice(0)
don't need to return as main array get changed */
function remove(arr) {
while(arr.length) {
arr.shift();
}
}
There are also tricky way which you can think about, for example something like this:
arr.splice(0, arr.length); //[]
So if arr has 5 items, it will splice 5 items from 0, which means nothing will remain in the array.
Also other ways like simply reassign the array for example:
arr = []; //[]
If you look at the Array functions, there are many other ways to do this, but the most recommended one could be changing the length.
As I said in the first place, you can also prototype remove() as it's the answer to your question. you can simply choose one of the methods above and prototype it to Array object in JavaScript, something like:
Array.prototype.remove = Array.prototype.remove || function() {
this.splice(0, this.length);
};
and you can simply call it like this to empty any array in your javascript application:
arr.remove(); //[]
If you are using
a = [];
Then you are assigning new array reference to a, if reference in a is already assigned to any other variable, then it will not empty that array too and hence garbage collector will not collect that memory.
For ex.
var a=[1,2,3];
var b=a;
a=[];
console.log(b);// It will print [1,2,3];
or
a.length = 0;
When we specify a.length, we are just resetting boundaries of the array and memory for rest array elements will be connected by garbage collector.
Instead of these two solutions are better.
a.splice(0,a.length)
and
while(a.length > 0) {
a.pop();
}
As per previous answer by kenshou.html, second method is faster.
There is a lot of confusion and misinformation regarding the while;pop/shift performance both in answers and comments. The while/pop solution has (as expected) the worst performance. What's actually happening is that setup runs only once for each sample that runs the snippet in a loop. eg:
var arr = [];
for (var i = 0; i < 100; i++) {
arr.push(Math.random());
}
for (var j = 0; j < 1000; j++) {
while (arr.length > 0) {
arr.pop(); // this executes 100 times, not 100000
}
}
I have created a new test that works correctly :
http://jsperf.com/empty-javascript-array-redux
Warning: even in this version of the test you can't actually see the real difference because cloning the array takes up most of the test time. It still shows that splice is the fastest way to clear the array (not taking [] into consideration because while it is the fastest it's not actually clearing the existing array).
Array.prototype.clear = function() {
this.length = 0;
};
And call it: array.clear();
In case you are interested in the memory allocation, you may compare each approach using something like this jsfiddle in conjunction with chrome dev tools' timeline tab. You will want to use the trash bin icon at the bottom to force a garbage collection after 'clearing' the array. This should give you a more definite answer for the browser of your choice. A lot of answers here are old and I wouldn't rely on them but rather test as in #tanguy_k's answer above.
(for an intro to the aforementioned tab you can check out here)
Stackoverflow forces me to copy the jsfiddle so here it is:
<html>
<script>
var size = 1000*100
window.onload = function() {
document.getElementById("quantifier").value = size
}
function scaffold()
{
console.log("processing Scaffold...");
a = new Array
}
function start()
{
size = document.getElementById("quantifier").value
console.log("Starting... quantifier is " + size);
console.log("starting test")
for (i=0; i<size; i++){
a[i]="something"
}
console.log("done...")
}
function tearDown()
{
console.log("processing teardown");
a.length=0
}
</script>
<body>
<span style="color:green;">Quantifier:</span>
<input id="quantifier" style="color:green;" type="text"></input>
<button onclick="scaffold()">Scaffold</button>
<button onclick="start()">Start</button>
<button onclick="tearDown()">Clean</button>
<br/>
</body>
</html>
And you should take note that it may depend on the type of the array elements, as javascript manages strings differently than other primitive types, not to mention arrays of objects. The type may affect what happens.
Use a modified version of Jan's initial suggestion:
var originalLength = A.length;
for (var i = originalLength; i > 0; i--) {
A.pop();
}
Terser:
for (let i = A.length; i > 0;A.pop(),i--) {}
Or here's another take:
while(!A[Symbol.iterator]().next().done)A.shift()
A.splice(0);
I just did this on some code I am working on. It cleared the array.
If you use constants then you have no choice:
const numbers = [1, 2, 3]
You can not reasign:
numbers = []
You can only truncate:
numbers.length = 0
To Empty a Current memory location of an array use: 'myArray.length = 0' or 'myArray.pop() UN-till its length is 0'
length : You can set the length property to truncate an array at any time. When you extend an array by changing its length property, the number of actual elements increases.
pop() : The pop method removes the last element from an array and returns that returns the removed value.
shift() : The shift method removes the element at the zeroeth index and shifts the values at consecutive indexes down, then returns the removed value.
Example:
var arr = ['77'];
arr.length = 20;
console.log("Increasing : ", arr); // (20) ["77", empty × 19]
arr.length = 12;
console.log("Truncating : ", arr); // (12) ["77", empty × 11]
var mainArr = new Array();
mainArr = ['1', '2', '3', '4'];
var refArr = mainArr;
console.log('Current', mainArr, 'Refered', refArr);
refArr.length = 3;
console.log('Length: ~ Current', mainArr, 'Refered', refArr);
mainArr.push('0');
console.log('Push to the End of Current Array Memory Location \n~ Current', mainArr, 'Refered', refArr);
mainArr.poptill_length(0);
console.log('Empty Array \n~ Current', mainArr, 'Refered', refArr);
Array.prototype.poptill_length = function (e) {
while (this.length) {
if( this.length == e ) break;
console.log('removed last element:', this.pop());
}
};
new Array() | [] Create an Array with new memory location by using Array constructor or array literal.
mainArr = []; // a new empty array is addressed to mainArr.
var arr = new Array('10'); // Array constructor
arr.unshift('1'); // add to the front
arr.push('15'); // add to the end
console.log("After Adding : ", arr); // ["1", "10", "15"]
arr.pop(); // remove from the end
arr.shift(); // remove from the front
console.log("After Removing : ", arr); // ["10"]
var arrLit = ['14', '17'];
console.log("array literal « ", indexedItem( arrLit ) ); // {0,14}{1,17}
function indexedItem( arr ) {
var indexedStr = "";
arr.forEach(function(item, index, array) {
indexedStr += "{"+index+","+item+"}";
console.log(item, index);
});
return indexedStr;
}
slice() : By using slice function we get an shallow copy of elements from the original array, with new memory address, So that any modification on cloneArr will not affect to an actual|original array.
var shallowCopy = mainArr.slice(); // this is how to make a copy
var cloneArr = mainArr.slice(0, 3);
console.log('Main', mainArr, '\tCloned', cloneArr);
cloneArr.length = 0; // Clears current memory location of an array.
console.log('Main', mainArr, '\tCloned', cloneArr);
I'm surprised no one has suggested this yet:
let xs = [1,2,3,4];
for (let i in xs)
delete xs[i];
This yields an array in quite a different state from the other solutions. In a sense, the array has been 'emptied':
xs
=> Array [ <4 empty slots> ]
[...xs]
=> Array [ undefined, undefined, undefined, undefined ]
xs.length
=> 4
xs[0]
=> ReferenceError: reference to undefined property xs[0]
You can produce an equivalent array with [,,,,] or Array(4)