Convert for loop to a while loop in JavaScript - javascript

I've been trying to convert the following JS code that uses a for loop to a while loop and/or do-while loop.
var unique = function(array)
{
var newArray = []
array.sort()
for(var x in array) if(array[x] != array[x-1]) newArray.push(array[x])
return newArray
}
The code is suppose to return only distinct names from an array of names that repeat. I've been trying to convert the for loop but so far I've been running into problems using this:
do
{
newArray.push(array[x])
}
while(array[x] != array[x-1])
return newArray;
Can anyone help me? Thanks!

Is it guaranteed that your names are only going to be duplicated in sequence i.e. is it true that if a name does have a duplicate it will be directly after it? If not, then checking the elements that are directly next to each will not find all the duplicates. You'll have to do a nested for loop or some other n^2 algorithm.
var duplicated = false;
for (int x = 0; x < array.length; x++)
{
for (int y = 0; y < array.length; y++)
{
if (array[x] == array[y])
{
duplicated = true;
}
}
if (!duplicated)
{
array.push(array[x]);
}
duplicated = false;
}
return newArray;
please note, this implementation is very poor but it gets the point across.

You're very close. The following preserves the original sequence:
function getUnique(array) {
var newArray = array.slice(); // copy original
var i = newArray.length - 1;
do {
if (newArray[i] == newArray[--i]) {
newArray.splice(i, 1);
}
} while(i)
return newArray;
}
Note that the above assumes a sorted, contiguous array (no missing members). If you can't be sure of that, sort newArray before the do..while loop and maybe compact it to make it contiguous.

A while loop doesn't make sense for your use case. A while loop is good when you want to loop as long as some condition is met and then stop the first time it fails. But a for loop is good when you want to loop through a certain number of items (for instance all of them).
So stick with a for loop. Also a few notes on while loops for whenever you do use them:
A for loop automatically updates the loop index which in your case is x. A while loop doesn't. So, to replicate your for loop, you would need to manually increment x.
Also, you test at the top of the for loop. To mirror that behavior you would want a while instead of a do- while (while tests before executing each loop, do-while tests after).
But if you used a while loop, you'd exit the loop the first time array[x] != array[x-1] failed. And it sounds like you don't want that. You want to push all values that meet that test.

Related

Should I include an if statement to prevent a redundant iteration in a loop?

You see, I've return this code to reverse the elements of an Array. This array takes two extreme elements and exchanges them like say [1,2,3,4] => [4,2,3,1] => [4,3,2,1]. However when there are odd number of elements there is a redundant iteration where it exchanges the middle element with the middle element itself. I know computers are a lot faster than say 100 years ago, but just in case would keeping my code as it is offset the efficiency gained by using an "if statement" to prevent that one extra iteration? You see I'm a newbie and wanted to know whether an if statement is more computationaly draining than a single extra iteration. Thank you in advance.
let arr = [1,2,3,4,5]
function reversearray(array){
for(let a=0; a < array.length-a; a++){
let total = array[array.length-a-1];
array[array.length-a-1] =array[a];
array[a]=total;
}
return array;
}
No, running an additional if statement for every array position to cover one case scenario is far more inefficient than allowing one "unnecessary" loop iteration.
Neither - make your loop run the correct number of times:
for(let a=0; a < Math.floor(array.length/2); a++){ …

Most efficient way to delete from array?

I have an array containing particles (fire, blood, smoke, etc.) in an HTML5 game. All particles have an expiry/lifespan. I'm creating up to 100 particles per frame at 60fps so I want to keep this array as clean as possible so I can loop through it efficiently.
I have heard it's better to use 'splice' rather than 'delete' to remove elements from an array. This makes sense to me as I'd rather not loop through keys of the array that are blank (that 'delete' leaves behind).
However, I tested this out and have a higher, more consistent frame rate if I 'delete' keys rather than splicing them to remove expired particles. The downside is the longer the game runs the longer my particles array gets.
Is there a better solution to this?
If the order of the items in the array doesn't matter, then simply assign the last item in the array to the one you want to overwrite and then delete it by reducing the .length.
function unordered_remove(arr, i) {
if (i <= 0 || i >= arr.length) {
return;
}
if (i < arr.length - 1) {
arr[i] = arr[arr.length-1];
}
arr.length -= 1;
}
This is much faster because it doesn't need to reindex and is good for situations where the order doesn't matter.
When you use delete on an array element, all you are actually doing is setting that array element to undefined. The array will still have the same length. When you use splice, you actually remove that element entirely. The element is removed, and everything after that element is shifted down 1 index.Of the two, delete is going to be faster since your array doesn't have to re-index.
As for performance, if leaving the deleted elements as undefined works, then that is probably the best way to do it. If you are concerned about the array length growing too long, or maybe have to search that array frequently and want to reduce overhead, you could periodically filter out the undefined elements like so:
function filterArr() {
myArr = myArr.filter(function(v) {
return typeof v !== 'undefined';
});
}
var interval = setInterval(filterArr, 5000);
This will give you the best of both worlds. When you need to remove the particles, you use delete to set the elements to undefined, which is faster than removing them in place. Every now and then, you remove them in place to keep your array size lower.
You could improve upon that depending on your requirements. Good luck :)
You'll have way higher performances by packing the array by yourself : less operations AND no need to dispose current array and create a new one (like Array.filter does), so much less garbage collection.
function packArray(tgtArray) {
if (!tgtArray || !tgtArray.length) return;
var srcIndex = 0;
var dstIndex = 0;
var arrayLength = tgtArray.length ;
do {
var currentItem = tgtArray[srcIndex];
if (currentItem.alive) {
if (srcIndex != dstIndex) {
tgtArray[dstIndex] = currentItem ;
}
dstIndex++;
}
srcIndex++;
} while (srcIndex != arrayLength) ;
dstIndex--;
tgtArray.length = dstIndex > 0 ? dstIndex : 0 ;
}

Javascript .pop() and .sort() not working right in a for loop

I'm trying to remove the last element in the array but it ends up putting the removed element back to the top of the list and some of the other elements are listed differently.
Same thing using the .sort() method. The output shows this sentence five times:
Tolstoy wrote War and Peace,Twain wrote Huckleberry Finn
var author_title = new Array(5)
author_title[0]="Tolstoy wrote War and Peace";
author_title[1]="Twain wrote Huckleberry Finn";
author_title[2]="Hardy wrote The Return of the Native";
author_title[3]="Dickens wrote A Christmas Carol";
author_title[4]="Uris wrote Exodus";
for(var count=0;count<author_title.length;count++) {
document.write(author_title.pop() + "<br>");
}
for(var count=0;count<author_title.length;count++) {
document.write(author_title.sort()+"<br>");
}
If you wanted to alter your array then use pop, writing a variable that is equivalent to array.length outside of the for loop, then setting your variable to that declared variable. You have to remember that you are changing your array every time you .pop(), thus changing the for-loop in each iteration. Also, the <br /> is for HTML so you may have just forgotten your self-closing tag on that
var length = array.length;
for( var i = 0; i > length; i++ ) {
document.write( array.pop() + "\n")
}
No part of this should work. for..in loops iterate over the keys for each properly, not the values. It's not meant for iterating over arrays. On my machine, it produces 0,1,2,etc.
You're also attempting to pop elements while iterating over the array. pop modifies the array, so your iterator will be invalidated on each iteration.
What you want is a simple for loop:
for (var i = 0; i < author_title.length; ++i) {
console.log(author_title[i]);
}

get sub array of array javascript

I have a array in javascript and I want a sub array of the array with element which are at position n*3, n=0,1,2.. for example if:
var arr = [1,2,3,4,5,6,7,8,9,10,11,12]
var subArr = [1,4,7,10]
Edit : any soln without looping.
Here's an example of a fancy way :
var brr = [1,2,3,4,5,6,7,8,9,10,11,12].filter(function(_,i){ return !(i%3) })
But a simple loop would have been as good (and would have been compatible with IE8). note that filter, even if it's not visible, does loop over the array. You can't avoid a loop (at least for an arbitrary sized array) even if you may disguise it.
Here's how you would do it with a standard loop :
var brr = [];
for (var i=0; i<arr.length; i+=3) brr.push(arr[i])
Performance is rarely a concern on such operations client side but you might find important to know that the for loop is much faster here : http://jsperf.com/looporfilter
In order to operate on a set of data of size n, m times, where m > 1, how would you avoid iteration? Really, there is no way unless you use a set of O(1) operations like this:
var arr = [1,2,3,4,5,6,7,8,9,10,11,12];
var subarr = [];
subarr.push(arr[0]);
subarr.push(arr[3]);
subarr.push(arr[6]);
subarr.push(arr[9]);
Here is a structural recursion (which can be represented by a loop, and does technically loop).
var arr = [1,2,3,4,5,6,7,8,9,10,11,12];
var subarr = [];
(function recur(n){
if( n >= arr.length ) return;
subarr.push(arr[n]);
recur(n+3);
})(0);
To note: a straight for loop will always be faster. In an expansion of #dystroy's jsperf, this recursion ran slower than the for loop, but faster than the filter. http://jsperf.com/looporfilter/2
just for kicks, i searched for a way to actually do it without a loop like the OP wanted.
without using a loop, it's tough.
the closest i could manage gets the right numbers, but converts them to Strings instead of numbers.
var r=[1,2,3,4,5,6,7,8,9,10,11,12,13,14];
alert( "".replace.call(r+",-0,-0,-0", /(\d+),\d+,?(\d+,|$)/g, "$1,")
.replace(/(,?\-0){1,4}$/g,"")
.split(",") );
//shows: 1,4,7,10,13
if you need strong numbers, it's easy, but i am not sure if adding .map(Number) after .split(",") would constitute a loop in your book, but this is the only version that actually finds the desired results without a loop.
this also only works on positive integers as coded.
again, more for fun than something i would recommend using; don't be afraid of loops...
Here's a solution with no loop:
var arr = [1,2,3,4,5,6,7,8,9,10,11,12];
// pickInterval is a function that automatically picks every "n"
// elements from an array, starting with the first element
var subArr = pickInterval( arr, 3 );
// now subArr is [1,4,7,10]
Simple, isn't it? And not a loop in sight.
Ah, but you ask, "What's the catch? You haven't implemented that pickInterval() function, have you? I bet there's a loop in it."
And you're right. Even if we write our pickInterval() function using some other function that doesn't look like a loop, that function will have a loop in it. And if that one just calls yet another function, eventually you will find a loop.
It may be turtles all the way down, but there's a loop underneath them all.
So, to implement pickInterval(), we could use either approach from #dystroy's answer. We can put the loop right inside the function:
function pickInterval( array, interval ) {
var result = [];
for( var i = 0, n = array.length; i < n; i += 3 )
result.push( array[i] );
return result;
}
Or we can use .filter():
function pickInterval( array, interval ) {
return array.filter( function( _, i ){
return !( i % 3 );
});
}
Of course there's still a loop here, down inside .filter(). It's just been hidden from us in the very same way that pickInterval() hides any loop from its caller.
And that's the real point. Use .filter(), use a for loop, use whatever you want, as long as you encapsulate it inside a function. Then the inner workings of that function don't matter so much. If you like the for loop because it's fast and easy to understand, use that. If you like the filter() version because it's interesting and elegant, use that. If you later need to use it on a very large array and it's running slow, you can replace it with the for loop version without affecting the code that uses pickInterval().
Whatever code you write for this or for something like it, don't put it inline. Make a function.

Do loops check the array.length every time when comparing i against array.length?

I was browsing around and I found this:
var i, len;
for(i = 0, len = array.length; i < len; i++) {
//...
}
My first thoughts are:
Why he did that? (it must be better for some reason)
Is it worth it? (I assume yes, why else he will do it this way?)
Do normal loops (the ones that don't cache the length) check the array.length each time?
A loop consisting of three parts is executed as follows:
for (A; B; C)
A - Executed before the enumeration
B - condition to test
C - expression after each enumeration (so, not if B evaluated to false)
So, yes: The .length property of an array is checked at each enumeration if it's constructed as for(var i=0; i<array.length; i++). For micro-optimisation, it's efficient to store the length of an array in a temporary variable (see also: What's the fastest way to loop through an array in JavaScript?).
Equivalent to for (var i=0; i<array.length; i++) { ... }:
var i = 0;
while (i < array.length) {
...
i++;
}
Is it worth it? (obviously yes, why else he will do it this way?)
Absolutely yes. Because, as you say, loop will calculate array length each time. So this will cause an enormous overhead. Run the following code snippets in your firebug or chrome dev tool vs.
// create an array with 50.000 items
(function(){
window.items = [];
for (var i = 0; i < 50000; i++) {
items.push(i);
}
})();
// a profiler function that will return given function's execution time in milliseconds
var getExecutionTime = function(fn) {
var start = new Date().getTime();
fn();
var end = new Date().getTime();
console.log(end - start);
}
var optimized = function() {
var newItems = [];
for (var i = 0, len = items.length; i < len; i++) {
newItems.push(items[i]);
}
};
var unOptimized = function() {
var newItems= [];
for (var i = 0; i < items.length; i++) {
newItems.push(items[i]);
}
};
getExecutionTime(optimized);
getExecutionTime(unOptimized);
Here is the approximate results in various browsers
Browser optimized unOptimized
Firefox 14 26
Chrome 15 32
IE9 22 40
IE8 82 157
IE7 76 148
So consider it again, and use optimized way :)
Note: I tried to work this code on jsPerf but I couldn't access jsPerf now. I guess, it is down when I tried.
I always thought in JavaScript length was just a property of the array object, pre-calculated by previous array operations - creation, addition, removal - or overridden by the user, so you're just looking up a variable anyway? I must admit I had just assumed that because of the lack of parenthesis, but looking at the MDN page for array.length, it seems to say the same thing.
In languages where length is a method or length is calculated by a standard library function, then you should pre-calculate the length before running the loop so The array isn't calculated every iteration, particularly for large datasets. Even then, in modern high level languages like Python, len() just returns the length property of the array object anyway.
So unless I'm mistaken, the complexity is just O(1), and from that standpoint, even if the variable were slightly faster than a property to lookup each pass, it wouldn't be worth the potential trouble of creating/reusing additional variables outside of the protective for loop scope.
However, I suspect that in this case the reason the example's programmer chose this approach is simply just a habit they picked up in another language and carried forwards JavaScript.
One reason to do this is say, if you're adding elements to the array during the loop but do not want to iterate over them. Say you want to turn [1, 2, 3] into [1, 2, 3, 1, 2, 3]. You could to that with:
var initialLength = items.length;
for(var i=0; i<initialLength; ++i) {
items.push(items[i]);
}
If you don't save the length before the loop, then array.length will keep increasing and the loop will run until the browser crashes / kills it.
Other than that, as the others said, it mildly affects performance. I wouldn't make a habit out of doing this because "premature optimization is the root of all evil". Plus, if you change the size of the array during the loop, doing this could break your code. For instance, if you remove elements from the array during the loop but keep comparing i to the previous array size, then the loop will try to access elements beyond the new size.
Yes
Its check the array.length every time, but if we don't want to run our loop for increased array then, in that case, we can use forEach method.
forEach is a javascript in build method which is does like for loop, but forEach only iterative the elements in an array which are before the loop start.
Let's understand this from below snippet:
array = [1,2,3,4]
for(i=0;i<=array.length;i++){
console.log(array[i]);
array.push(array[i]+1);
}
output like
1
2
3
4
5
6
...so on (infinite) while its checking array.length each time
let's check with forEach method
array = [1,2,3,4]
array.forEach((element) => {
console.log(element);
array.push(element+1);
})
console.log("array elements after loop",array);
it only processes for 4 elements which are present in array before iteration start.
**but in forEach case, it will affect on array.length if we pop out the element from array.
lets see this by an example:
array = [1,2,3,4]
array.forEach((element) => {
console.log(element);
array.pop()
})
console.log("array elements after loop",array);
Here are a number of performance tests for different approaches
http://www.websiteoptimization.com/speed/10/

Categories

Resources