Most computationally efficient way to find last element in a JavaScript Array? - javascript

Would it be faster to use
var lastelement = myarray[myarray.length - 1];
or
var lastelement = myarray.reverse()[0];
and why?

Just think about it.
If you know how long an array is, it is much faster to just get the last value than to have to compute the reverse!

It is faster to access an element by its index, as it should have O(1) complexity. Reversing an array and then accessing the first index, on the other hand, would have at least O(n) complexity, depending on how the reversing algorithm is implemented.

I'll take this from a different angle than has been answered here. Chances are you just want to get the last element, you don't want to do anything to the actual array itself. If you use array.reverse to get the last element, you are actually changing the array (probably an unpleasant side effect in your case).
var myArray = [.....]; // some array
var lastElement = myArray.reverse()[0]; // get the last element
var firstElement = myArray[0]; // tricked you! This is now the same as
// lastElement because the myArray object
// in memory has been reversed.
So if you want to get the last element without changing the array you'd have to do this:
var myArray = [.....]; // some array
var lastElement = myArray.slice().reverse()[0]; // copy and get the last element
var firstElement = myArray[0]; // this is the correct first element
Pretty obvious which way is more efficient now.

Array.reverse() replacing old array with new reversed array in same reference ,crating the new array with new elements is much slower than get array element by index.
var lastelement = myarray[myarray.length - 1];
Is much faster.

The real efficient solution is to use a red and black binary tree (http://en.wikipedia.org/wiki/Red%E2%80%93black_tree ) where you'll store in each node one array value, the delta with the previous and next item, as well as the relative position to median. Then with only a few traversal you should be able to identify the last element (last element is the one having an index with biggest spread to median index, while having a previous item and no next item).
The trick is that each traversal takes only O(ln(n)) and since you do less than ln(n) traversal, time is below O(sq(ln(n))), so it's very fast.
Edit : following Bergi's constructive comments, i just wonder if it wouldn't be faster to just use arrays for this, by using a Fast fourier transform on an array containing all indexes of the array, then identifying last element with a frequency analysis, then convert back the array to get the number out of the frequency. I apologize if i'm unclear, i don't see clearly all steps at the time of writing, but i think it's a idea worth following.

Related

Is there a way to map a value in an object to the index of an array in javascript?

Prepending that a solution only needs to work in the latest versions of Chrome, Firefox, and Safari as a bonus.
-
I am trying to use an associative array for a large data set with knockout. My first try made it a true associative array:
[1: {Object}, 3: {Object},...,n:{Object}]
but knockout was not happy with looping over that. So I tried a cheating way, hoping that:
[undefined, {Object}, undefined, {Object},...,{Object}]
where the location in the array is the PK ID from the database table. This array is about 3.2k items large, and would be iterated over around every 10 seconds, hence the need for speed. I tried doing this with a splice, e.g.
$.each(data, function (index, item) {
self.myArray.splice(item.PKID, 0, new Object(item));
}
but splice does not create indices, so since my first PKID is 1, it is still inserted at myArray[0] regardless. If my first PK was 500, it would start at 0 still.
My second thought is to initialize the array with var myArray = new Array(maxSize) but that seems heavy handed. I would love to be able to use some sort of map function to do this, but I'm not really sure how to make the key value translate into an index value in javascript.
My third thought was to keep two arrays, one for easy look up and the other to store the actual values. So it combines the first two solutions, almost, by finding the index of the object in the first example and doing a lookup with that in the second example. This seems to be how many people manage associative arrays in knockout, but with the array size and the fact that it's a live updating app with a growing data set seems memory intensive and not easily manageable when new information is added.
Also, maybe I'm hitting the mark wrong here? We're putting these into the DOM via knockout and managing with a library called isotope, and as I mentioned it updates about every 10 seconds. That's why I need the fast look up but knockout doesn't want to play with my hash table attempts.
--
clarity edits:
so on initial load the whole array is loaded up (which is where the new Array(maxLength) would go, then every 10 seconds anything that has changed is loaded back. That is the information I'm trying to quickly update.
--
knockout code:
<!-- ko foreach: {data: myArray(), afterRender: setInitialTileColor } -->
<div class="tile" data-bind="attr: {id: 'tileID' + $data.PKID()}">
<div class="content">
</div>
</div>
<!-- /ko -->
Then on updates the hope is:
$.each(data.Updated, function (index, item) {
var obj = myModel.myArray()[item.PKID];
//do updates here - need to check what kind of change, how long it's been since a change, etc
}
Here is a solution how to populate array items with correct indexes, so it doesn't start from the first one (0 (zero) I meant)
just use in loop
arr[obj.PKID] = obj;
and if your framework is smart (to use forEach but not for) it will start from your index (like 500 in case below)
http://jsfiddle.net/0axo9Lgp/
var data = [], new_data = [];
// Generate sample array of objects with index field
for (var i = 500; i < 3700; i++) {
data.push({
PKID: i,
value: '1'
});
}
data.forEach(function(item) {
new_data[item.PKID] = item;
});
console.log(new_data);
console.log(new_data.length); // 3700 but real length is 3200 other items are undefined
It's not an easy problem to solve. I'm assuming you've tried (or can't try) the obvious stuff like reducing the number of items per page and possibly using a different framework like React or Mithril.
There are a couple of basic optimizations I can suggest.
Don't use the framework's each. It's either slower than or same as the native Array method forEach, either way it's slower than a basic for loop.
Don't loop over the array over and over again looking for every item whose data has been updated. When you send your response of data updates, send along an array of the PKIds of the updated item. Then, do a single loop:
.
var indexes = []
var updated = JSON.parse(response).updated; // example array of updated pkids.
for(var i=0;i<allElements.length;i++){
if(updated.indexOf(allElements[i].pkid)>-1)
indexes.push(i);
}
So, basically the above assumes you have a simple array of objects, where each object has a property called pkid that stores its ID. When you get a response, you loop over this array once, storing the indexes of all items that match a pk-id in the array of updated pk-ids.
Then you only have to loop over the indexes array and use its elements as indexes on the allElements array to apply the direct updates.
If your indexes are integers in a reasonable range, you can just use an array. It does not have to be completely populated, you can use the if binding to filter out unused entries.
Applying updates is just a matter of indexing the array.
http://jsfiddle.net/0axo9Lgp/2/
You may want to consider using the publish-subscribe pattern. Have each item subscribe to its unique ID. When an item needs updating it will get the event and update itself. This library may be helpful for this. It doesn't depend upon browser events, just arrays so it should be fairly fast.

Checking if element exists in array without iterating through it

my array:
tempListArray = "[{"id":"12","value":false},{"id":"10","value":false},{"id":"9","value":false},{"id":"8","value":false}]";
To check if an element exists I would do this:
for (var i in tempListArray) {
//check flag
if (tempListArray[i].id == Id) {
flagExistsLoop = 1;
break;
}
}
Is there anyway, I can check if an Id exists without looping through the whole array. Basically I am worried about performance if say I have a 100 elements.
Thanks
No, without using custom dictionary objects (which you seriously don't want to for this) there's no faster way than doing a 'full scan' of all contained objects.
As a general rule of thumb, don't worry about performance in any language or any situation until the total number of iterations hits 5 digits, most often 6 or 7. Scanning a table of 100 elements should be a few milliseconds at worst. Worrying about performance impact before you have noticed performance impact is one of the worst kinds of premature optimization.
No, you can't know that without iterating the array.
However, note for...in loops are a bad way of iterating arrays:
There is no warranty that it will iterate the array with order
It will also iterate (enumerable) non-numeric own properties
It will also iterate (enumerable) properties that come from the prototype, i.e., defined in Array.prototype and Object.protoype.
I would use one of these:
for loop with a numeric index:
for (var i=0; i<tempListArray.length; ++i) {
if (tempListArray[i].id == Id) {
flagExistsLoop = 1;
break;
}
}
Array.prototype.some (EcmaScript 5):
var flagExistsLoop = tempListArray.some(function(item) {
return item.id == Id;
});
Note it may be slower than the other ones because it calls a function at each step.
for...of loop (EcmaScript 6):
for (var item of tempListArray) {
if (item.id == Id) {
flagExistsLoop = 1;
break;
}
}
Depending on your scenario, you may be able to use Array.indexOf() which will return -1 if the item is not present.
Granted it is probably iterating behind the scenes, but the code is much cleaner. Also note how object comparisons are done in javascript, where two objects are not equal even though their values may be equal. See below:
var tempListArray = [{"id":"12","value":false},{"id":"10","value":false},{"id":"9","value":false},{"id":"8","value":false}];
var check1 = tempListArray[2];
var check2 = {"id":"9","value":false};
doCheck(tempListArray, check1);
doCheck(tempListArray, check2);
function doCheck(array, item) {
var index = array.indexOf(item);
if (index === -1)
document.write("not in array<br/>");
else
document.write("exists at index " + index + "<br/>");
}
try to use php.js it may help while you can use same php function names and it has some useful functionalities
There is no way without iterating through the elements (that would be magic).
But, you could consider using an object instead of an array. The object would use the (presumably unique) id value as the key, and the value could have the same structure you have now (or without the redundant id property). This way, you can efficiently determine if the id already exists.
There is a possible cheat for limited cases :) and it is magic...cough cough (math)
imagine you have 3 elements:
1
2
3
and you want to know if one of these is in an array without iterating it...
we could make a number that contains a numerical flavor of the array. we do this by assigning prime numbers to the elements:
1 - 2
2 - 3
3 - 5
the array so when we add item 2 we check that the array doesn't already contain the prime associated to that item by checking (if Flavor!=0 && (Flavor%3)!=0) then adding the prime Flavor*=3;
now we can tell that the second element is in the array by looking at the number.
if Flavor!=0 && (Flavor%3)==0 // its There!
Of course this is limited to the numerical representation that can be handled by the computer. and for small array sizes (1-3 elements) it might still be faster to scan. but it's just one idea.
but the basis is pretty sound. However, this method becomes unusable if you cannot correlate elements one to one with a set of primes. You'll want to have the primes calculated in advance. and verify that the product of those is less numerical max numerical representation. (also be careful with floating-point. because they might not be able to represent the number at the higher values due to the gaps between representable values.) You probably have the best luck with an unsigned integer type.
This method will probably be too limiting. And there is something else you can do to possibly speed up your system if you don't want to iterate the entire array.
Use different structures:
dictionaries/maps/trees etc.
if your attached to the array another method can be a bloom filter. This will let you know if an element is not in your set, which can be just as useful.

Count number of elements in an array using Javascript

I have an assignment for a Javascript course where I have to count how many of each specific types of elements occur in an array. The array is 105 elements long, and just occurrences of the numbers 1, 2, 3, 4, and 5. I have to count how many 1's, 2's, 3's, etc.
Of course there's a simple way to do this using a loop however my teacher has added the following at the end of the assignment:
Use only the length property, toString(), sort() and indexOf() methods. Please no loops or conditional statements.
I have no idea how to do this assignment without using a loop. Any help you can give me is greatly appreciated. Thanks!
this will be the answere:
var c=[1,2,3,4,5,2,3,4,5]
c.sort()
cout_of_1 = c.indexOf(2)-c.indexOf(1);
cout_of_2 = c.indexOf(3)-c.indexOf(2);
cout_of_3 = c.indexOf(4)-c.indexOf(3);
cout_of_4 = c.indexOf(5)-c.indexOf(4);
cout_of_5 = c.length-c.indexOf(5)+1;
Since this is an assignment and you haven't really shown an attempt, I'll just give you a couple of hints.
Once you sort the array, all of the 1s will be grouped together at the start of the array, then all the 2s, etc.
The indexOf function returns the first index at which a given element can be found in the array, or -1 if it is not present.
Given the index of the first occurrence of each digit in a sorted array, you should be able to calculate how many of each digit there are. I'm not sure you'll need toString() at all. Your instructor might have thrown that in to be sneaky.
First, sort the array, then grab the first occurrence of the next value. That's the amount of numbers you have, minus the ones you already have.
var array = [1,2,5,3,2,4,5,2,1,3,3,4,5,6,2];
array = array.sort();
var ones = array.indexOf(2);
var twos = array.indexOf(3) - ones;
var threes = array.indexOf(4) - ones - twos;
...
However for the last value (5) there is no next value to check. You can work around this by checking the length and subtracting one from it.
var fives = array.length - ones - twos - threes - fours;
Keep in mind that this is actually bad code, and you should use loops.

JS Slice only removes Items when they were in the Constructor

I try to remove the first Item so that all other move up in an Array I create with
..
Queue: [],
..
and dynamically push Items into.
I later use slice to remove them and have then next Item be the first one.
..
thread.Queue.slice(0, 1);
..
It should return the first Item of the Array, which it does, but it should also remove it from the array and move all other up.
Here is a example which shows, that is neither working in the Browser. (I found this 'behaviour' in Node.js)
http://jsfiddle.net/bTrsE/
or rather
http://gyazo.com/b3dcdbf4f74642c04fe1c1025f225a08.png
Array.Slice = Is an implementation of SubArray, From an array you want to extract certain elements from the index and return a new array.
Example:
var cars = ['Nissan','Honda','Toyota'];
var bestCars = cars.splice(0,1);
console.log(bestCars);
//This should output Nissan Because i like Nissan
For your problem you should be looking Array.Splice(), splice adds / removes an element from the index
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/splice
The .slice() method does not alter the original array. It returns a shallow copy of the portion of the array you asked for.

JavaScript - Get all but last item in array

This is my code:
function insert(){
var loc_array = document.location.href.split('/');
var linkElement = document.getElementById("waBackButton");
var linkElementLink = document.getElementById("waBackButtonlnk");
linkElement.innerHTML=loc_array[loc_array.length-2];
linkElementLink.href = loc_array[loc_array.length];
}
I want linkElementLink.href to grab everything but the last item in the array. Right now it is broken, and the item before it gets the second-to-last item.
I’m not quite sure what you’re trying to do. But you can use slice to slice the array:
loc_array = loc_array.slice(0, -1);
Use pathname in preference to href to retrieve only the path part of the link. Otherwise you'll get unexpected results if there is a ?query or #fragment suffix, or the path is / (no parent).
linkElementLink.href= location.pathname.split('/').slice(0, -1).join('/');
(But then, surely you could just say:)
linkElementLink.href= '.';
Don't do this:
linkElement.innerHTML=loc_array[loc_array.length-2];
Setting HTML from an arbitrary string is dangerous. If the URL you took this text from contains characters that are special in HTML, like < and &, users could inject markup. If you could get <script> in the URL (which you shouldn't be able to as it's invalid, but some browser might let you anyway) you'd have cross-site-scripting security holes.
To set the text of an element, instead of HTML, either use document.createTextNode('string') and append it to the element, or branch code to use innerText (IE) or textContent (other modern browsers).
If using lodash one could employ _.initial(array):
_.initial(array): Gets all but the last element of array.
Example:
_.initial([1, 2, 3]);
// → [1, 2]
Depending on whether or not you are ever going to reuse the array you could simply use the pop() method one time to remove the last element.
linkElementLink.href = loc_array[loc_array.length]; adds a new empty slot in the array because arrays run from 0 to array.length-1; So you returning an empty slot.
linkElement.innerHTML=loc_array[loc_array.length-2]; if you use the brackets you are only getting the contents of one index. I'm not sure if that is what you want? The next section tells how to get more than one index.
To get what you want you need for the .href you need to slice the array.
linkElementLink.href = loc_array.slice(0,loc_array.length-1);
or using a negative to count from the end
linkElementLink.href = loc_array.slice(0,-1);
and this is the faster way.
Also note that when getting to stuff straight from the array you will get the same as the .toString() method, which is item1, item2, item3. If you don't want the commas you need to use .join(). Like array.join('-') would return item1-item2-item3. Here is a list of all the array methods http://www.w3schools.com/jsref/jsref_obj_array.asp. It is a good resource for doing this.
.slice(number you want)
if you just want the first 4 elements in an array its array.slice(3)
doing a negative number starts from the end of the array

Categories