I used nodeJs to do some simple data processing. Links are array with objects with a source and a target.
For example:
Links=[{source: 'a', target: 'b'},{source: 'b', target: 'c'}]
Now i want to add 4 link to links but it did not work
for(var i=0;i<Links.length;i++){
for(var j=0;j<2;j++){
Links.push({
source: 'yo',
target: 'yo'
});
}
}
The entire program stuck here (goes for infinite loop).
Very simply you are adding items to the list you are pushing to so you can never reach the end. The simplest way around would be to save the length of the array to a variable and use that rather than calculating Links.length with every iteration.
Using the length property of an array will cause an infinite loop if you add items to the array in the loop. You should store the length in a variable instead of using the length in the condition.
Using nested loops in this situation might cause issues if there are more than two elements in the array. At the moment, you add two element for each element already in the array. It means it will add 6 links it there were 3 links in the array at the start of the loop, 8 if there were 4, and so on.
You could do some like this to strickly append 4 links to your array no matter how many link there were at the start.
startLength = Link.length;
do {
Link.push({
source:'yo',
target:'yo'
});
} while (Link.length < startLength + 4);
Related
I am using jQuery and got an response from API by using $.ajax. I want to grab the Arrays length from inside each object and display that in the html page. This is what I have done so far.
Here is the API response, i did breakdown of the last object, which contains an array and player names:
{_type: "InjuredPlayers", flaggedTokens: Array(1)} //1 injured player name
{_type: "InjuredPlayers", flaggedTokens: Array(3)} //3 injured players names
{_type: "InjuredPlayers", flaggedTokens: Array(5)} //5 injured players names
{_type: "InjuredPlayers", flaggedTokens: Array(2)} //2 injured players names
>flaggedTokens:Array(2)
>0:{offset: 0, token: "John", type:"UnknownToken"}
>1:{offset: 1, token: "Adam", type:"UnknownToken"}
length: 2
>_proto_:Array(0)
_type: "InjuredPlayers"
>_proto_: Object
In order to grab the length of the Array I can do any of these 2 methods according to this Get length of array inside object
console.log(response.flaggedTokens.length)
1
3
5
2
OR
console.log(response["flaggedTokens"].length)
1
3
5
2
My Failed Attempts: I assigned this output to a variable and tried to loop through and output by doing this:
$.ajax(gameResponse).done(function(response) {
let injuredPlayers = response.flaggedTokens.length;
let injuredPlayersArray = [];
for (let i = 0; i < injuredPlayers.length; i++) {
injuredPlayersArray.push(injuredPlayers[i])
}
$('.injured_players').html(injuredPlayersArray[i])
})
<div class="container">
Team One Total number: <span class="injured_players"></span> //should be 1
Team Two Total number: <span class="injured_players"></span> //should be 3
Team Three Total number:<span class="injured_players"></span> //should be 5
Team Four Toal number: <span class="injured_players"></span> //should be 2
</div>
Clearly I made some mistake which I can't seem to figure this out by myself. I was hoping if someone can guide me through the right direction.
To start with, in your for loop, you are returning the push action, but that's unnecessary and it kills the loop on the first iteration. Also, you have already set the length of the array to a new variable, but then in your for loop, you try to get the length of the new variable. Lastly, you declare injuredPlayersArray in your ajax statement, but based on your post, you recieved 4 separate api responses, so it should be declared outside of your ajax call so that the array doesn't get overwritten with every new call. And you don't need a for loop as you're only working with one array. Here is what it should look like.
let injuredPlayersArray = [];
$.ajax(gameResponse).done(function(response) {
let injuredPlayers = response.flaggedTokens.length;
injuredPlayersArray.push(injuredPlayers)
})
Your other mistake is that you are trying to dynamically display the value in the proper html tag, but you're setting the value for every span tag at the same time. So after your loop is finished, they would all say 2.
To fix that you can add a for loop after all of your api calls are completed (aka NOT inside a $.ajax().done()):
for (let i = 0; i < injuredPlayersArray.length; i++) {
$('.injured_players').eq(i).html(injuredPlayersArray[i])
}
Note: .eq() returns a set of DOM elements that match the selector it is called upon. So $('.injured_players') matches 4 elements on your page and in your for loop, it finds the i-th element in that set (so index 0 is equal to the first span tag) and sets the html for that element.
Note 2: There is an assumption I had to make with your api calls. From the way your api call is storing the length of the flaggedToken array in your response, it seems each ajax response returns a single object with the array of injured players and that you will have 4 separate api calls. However, if that's not the case and the response returns a array of objects, you will need to iterate over the array and get the length for every array in every object one at a time. You can also then ignore my suggestion to move the declaration of injuredPlayersArray to outside the api call. And the second for loop i wrote would go inside the api call.
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.
i am trying to remove some items in an json object list, the ones that have a specific group. My JSON looks like this.
var events = [
{"id":"19","name":"sports","group":"1"},
{"id":"20","name":"school","group":"2"},
{"id":"21","name":"fun","group":"1"}
]
I tried this
for(var i in events)
if(events[i].group == deleted_group)
events.splice(i, 1);
But the problem of this, is that if i have to remove more items, it bugs out. Is there another easy way to to this ? I am open for sugestion even using underscore.js .
Thank you in advance, Daniel!
Try this
var events = [
{"id":"19","name":"sports","group":"1"},
{"id":"20","name":"school","group":"2"},
{"id":"21","name":"fun","group":"1"}
]
console.log(_.reject(events, function(event){ return event.group == '1'; }));
When you're using the "splice" function to remove elements from the array inside a for loop,
you need to shift your current index back when removing an item since the array is reindexed.
Also take a look at the array functions like "filter" for a more convenient way, read more on MDN.
You can use delete operator to delete objects (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/delete):
delete events[0]
The problem with delete is, that in your array, as a value of events[0] it will leave undefined.
So another way (the way I would choose for your simple example) is to just rewrite the array:
var temp_events = [];
for(var i in events)
if(events[i].group != deleted_group)
temp_events[temp_events.length] = events[i];
events = temp_events;
Executing splice in a for loop has complexity n^2 (where n is number of elements). Rewriting has linear complexity.
I am trying to push elements onto an array.
EDIT
task.prototype.goTest=function(){
for(a = 0; a < test.length; a++) {
if(this.testnumber != test[a].number) {
//it will only loop 8 times under conditional statement
group = {
title: test[a].Title,
ID: test[a].ID,
contents: []
};
this.company.push(group);
this.testnumber = test.number[a];
}
//outside of if conditional statement.. it will loop 15 times
//i want every test[a].conetents get pushed to group.contents array.
//this.company is the final variable I need for this function...
group.contents.push(test[a].contents);
}
console.log(this.company);
}
However, when I do
console.log(this.company);
I see 8 elmements with only 1 element in each group.contents array. The ideal situation is to have 8 elements with 2 to 3 elements in the group.contents array.
this refers to the object in the function.
Any idea how to solve my issue?
You are making a new group object each loop, so the reference to group.contents is only the current one, it does not reference the previously created group objects.
So, each time you call group.contents.push, you are only pushing onto the object created in that loop iteration.
I need help with a loop... it's probably simple but I'm having difficulty coding it up.
Basically, I need to check existing Ids for their number so I can create a unique id with a different number. They're named like this: id="poly'+i'" in sequence with my function where i is equal to the number of existing elements. Example: Array 1, Array 2, Array 3 corresponding with i=1 for the creation of Array 1, i=2 for Array 2, etc.
Right now i is based on the total number of existing elements, and my "CreateNew" function is driven off x=i+1 (so the example above, the new element will be named Array 4). The problem is that if you delete one of the middle numbers, the "Create" function will duplicate the high number. i.e. Array 1, 2, 3 delete 2, create new-> Array 1, 3, 3.
I need an if() statement to check if the array already exists then a for() loop to cycle through all i's until it validates. Not sure how to code this up.
The code I'm trying to correct is below (note I did not write this originally, I'm simply trying to correct it with my minimal JS skills):
function NewPanel() {
var i = numberOfPanels.toString();
var x = (parseInt(i)+1).toString();
$('#items').append('<div onclick="polygonNameSelected(event)" class="polygonName" id="poly'+i+'"> Array '+ x +' </div>');
$('div[id*=poly]').removeClass('selected');
$('#poly'+i).addClass('selected');
$('#poly'+i).click(function() {
selectedPolygon = i;
$('div[id*=poly]').removeClass('selected');
$(this).addClass('selected');
});
}
THANK YOU! :)
Please clarify "The problem is that if you delete one of the middle numbers, ". What do you mean by delete? Anyway, the simplest solution is to create two arrays. Both arrays will have the same created id's. Whenever an id is created in the first array, an id will be added to the second array. So when it is deleted from first array, check your second array's highest value and then create this id in first array. I hope this did not confuse you.
Well it is hard to tell why you cannot just splice the array down. It seems to me there is a lot of extra logic involved in the tracking of element numbers. In other words, aside from the index being the same, the ids become the same as well as other attributes due to the overlapping 1, 3, 3 (from the example). If this is not the case then my assumption is incorrect.
Based on that assumption, when I encounter a situation where I want to ensure that the index created will always be an appending one, I usually take the same approach as I would with a database primary key. I set up a field:
var primaryKeyAutoInc = 0;
And every time I "create" or add an element to the data store (in this case an array) I copy the current value of the key as it's index and then increment the primaryKeyAutoInc value. This allows for the guaranteed unique indexing which I am assuming you are going for. Moreover, not only will deletes not affect future data creation, the saved key index can be used as an accessor.