For Each loop in JavaScript are making me mad - javascript

My problem is pretty simple.
I'm trying to update a list of objects (localDatz) with another list of objects received after an AJAX request (data).
So It consists in two loops.. But when I try to update two objects, only one object is updated. There is something I really don't understand.
Any help ?
// fetch the localdata first
var localData = getAll();
// Loop through my 'localData'
$.each(localData.features, function(index,feature){
// Loop through the new data that are received
$.each(data.features, function(){
newFeature = this;
if (feature.properties.id==newFeature.properties.id){
// i think here is the problem..but can't figure out how to fix it
// I remove the old feature and push the new one
localData.features.splice(index,1);
localData.features.push(newFeature);
}
});
});

You are modyfing the list which you loop over with this code:
if (feature.properties.id==newFeature.properties.id){
localData.features.splice(index,1);
localData.features.push(newFeature);
}
and not only modyfing the list entries, but the order as well (you push to the end of the list), which messes up .forEach loop. Use simply:
if (feature.properties.id==newFeature.properties.id){
localData.features[ index ] = newFeature;
}
There is no need for using .splice at all.

Related

Fastest way to iterate through the oldest items in an array? (Fastest implementation of a queue)

See edit too
I'm working in JavaScript but readable psuedocode of any kind may be able to answer my question.
I'm going to struggle describing this so please feel free to comment clarifications - I will answer them and refine my post accordingly.
Essentially, I have an array that acts as a queue, items are added, and when they are processed they need to be removed and more will eventually be added. What is the fastest way to get the first item in an array when I don't care about the index? I just want to iterate on a first-added basis without having to shift all entries in the array down each time. Also worth mentioning I am not looping through the array, I have a master loop for my app that checks if the array has items on each loop, and if it does, it will grab that data then remove it from the array. Currently to do this quickly I use pop, but now recognize I need to get the oldest item in the queue first each time, not the newest.
For more clarification if needed:
In my app I have blocks of raw data that first need to be ran through a function to be ready to be used by other parts of my app. Each block has a unique ID that I pass to the function in order for it to be parsed. For optimization purposes I only parse the blocks of data as it is needed.
In order to do this, my current system is when I realize I need a block to be parsed, I push its unique ID into an array, then a continuous loop in my app checks said array constantly, seeing if it has items in it. If it does, it pops the last item of the array and passes the unique id into the parsing function.
For performance reasons, on each iteration of the loop, only one block of data can be parsed. The issue arises when multiple blocks of data are in queue array already, and I add more items to the array before the loop can finish passing the already existing ID's in the array to the function. Basically, new ID's that are needed to be parsed are added to the end of the array before my loop can clear them out.
Now, this isn't all too bad because new data is needed somewhat sparsely, but when it is, lots of ID's are added at once, and this is an attribute of the app I can't really change.
Since I'm using pop, the most recently added ID is obviously always parsed first, but I chose this method as I believed it to be the fastest way to iterate a queue like this. However, I've come to realize I would rather parse the oldest items in the list first.
In essence, I'm looking for a way to loop through an array oldest to newest without having to re-organize the array each time. The index of the array is not important, I just need first-added, first-parsed behavior.
For example, I know I could always just pass the 0th item in the array to my function then shift the rest of the entries down, however, I believe having to shift down the rest of the items in the array is too costly to performance and not really worth it. If I'm just dumb and that should have no real-world cost please let me know, but still it seems like a band-aid fix. I'm certain there is a better solution out there.
I'm open to other data structures too as the array only holds strings.
Thank you
EDIT: While doing more googling I'm having a face palm moment and realized the problem I'm describing is a stack vs a queue. But now my question moves to what is the fastest implementation of a queue when the index isn't really of value to me?
The following is the FIFO queue implementation using singly linked list in javascript.
For more information of linked list -> https://www.geeksforgeeks.org/linked-list-set-1-introduction/
// queue implementation with linked list
var ListNode = function(val,next = null){
this.val = val
this.next = next
};
var Queue = function(){
let head = null;
let tail = null;
this.show = function(){
let curr = head;
let q = [];
while(curr){
q.push(curr.val);
curr = curr.next;
}
return q.join(' -> ');
}
this.enqueue = function(item){
let node = new ListNode(item);
if(!head) {
head = node;
tail = node;
} else {
tail.next = node;
tail = node;
}
}
this.dequeue = function(){
if(!head) return null;
else {
let first = head;
head = head.next;
first.next = null;
return first;
}
}
}
var myQueue = new Queue();
myQueue.enqueue(1); // head -> 1
console.log(myQueue.show())
myQueue.enqueue(2); // head -> 1 -> 2
console.log(myQueue.show())
myQueue.enqueue(3); // head -> 1 -> 2 -> 3
console.log(myQueue.show())
myQueue.dequeue(); // head -> 2 -> 3
console.log(myQueue.show())

Convert array of array objects into array of objects

I've spent the last couple hours going through some very similar answers to the above question but after a few implementations of loops and reduce I still have not gotten the solution I need.
I am getting an array of objects via service calls. I am pushing those controller array objects to another array because I need a single array to load data into a multi select. I.E.
StatesService.getAreaCities().then(function(response) {
controller.cities = response.data.rows;
controller.areaOptions.push(controller.cities);
});
StatesService.getAreaStates().then(function(response) {
controller.states = response.data.rows;
controller.areaOptions.push(controller.states);
});
controller.areaOptions = [];
This is an example of how I expect and need my array object to look.
With no modification this is how my array looks with those array objects pushed in.
How do I get the above data structure like the 1st image, an array of objects? I tried a solution with reduce()
var newCities = controller.cities.reduce(function(city){
return controller.city;
}, {});
controller.areaOptions.push(newCities);
but it wasnt what I was looking for because it returned a single object with all city property and all its values. I need each object to contain city and its value.
EDIT
I figured out the solution! Thanks to Lex.
I looped over each object in the array in each service and pushed the property.
Thanks to all for steering me in the right direction to figure this out, even the person that downvoted me :)
StatesService.getAreaCities().then(function(response) {
controller.cities = response.data.rows;
controller.cities.forEach(function(city){
controller.areaOptions.push(city);
});
});
Looks like response.data.rows is an array. So when you push response.data.rows into controller.areaOptions you are adding the rows array as an array element. (Basically making it a 2-dimensional array)
You should use Array.prototype.concat

Creating a filterable list with RxJS

I'm trying to get into reactive programming. I use array-functions like map, filter and reduce all the time and love that I can do array manipulation without creating state.
As an exercise, I'm trying to create a filterable list with RxJS without introducing state variables. In the end it should work similar to this:
I would know how to accomplish this with naive JavaScript or AngularJS/ReactJS but I'm trying to do this with nothing but RxJS and without creating state variables:
var list = [
'John',
'Marie',
'Max',
'Eduard',
'Collin'
];
Rx.Observable.fromEvent(document.querySelector('#filter'), 'keyup')
.map(function(e) { return e.target.value; });
// i need to get the search value in here somehow:
Rx.Observable.from(list).filter(function() {});
Now how do I get the search value into my filter function on the observable that I created from my list?
Thanks a lot for your help!
You'll need to wrap the from(list) as it will need to restart the list observable again every time the filter is changed. Since that could happen a lot, you'll also probably want to prevent filtering when the filter is too short, or if there is another key stroke within a small time frame.
//This is a cold observable we'll go ahead and make this here
var reactiveList = Rx.Observable.from(list);
//This will actually perform our filtering
function filterList(filterValue) {
return reactiveList.filter(function(e) {
return /*do filtering with filterValue*/;
}).toArray();
}
var source = Rx.Observable.fromEvent(document.querySelector('#filter'), 'keyup')
.map(function(e) { return e.target.value;})
//The next two operators are primarily to stop us from filtering before
//the user is done typing or if the input is too small
.filter(function(value) { return value.length > 2; })
.debounce(750 /*ms*/)
//Cancel inflight operations if a new item comes in.
//Then flatten everything into one sequence
.flatMapLatest(filterList);
//Nothing will happen until you've subscribed
source.subscribe(function() {/*Do something with that list*/});
This is all adapted from one of the standard examples for RxJS here
You can create a new stream, that takes the list of people and the keyups stream, merge them and scans to filter the latter.
const keyup$ = Rx.Observable.fromEvent(_input, 'keyup')
.map(ev => ev.target.value)
.debounce(500);
const people$ = Rx.Observable.of(people)
.merge(keyup$)
.scan((list, value) => people.filter(item => item.includes(value)));
This way you will have:
-L------------------ people list
------k-----k--k---- keyups stream
-L----k-----k--k---- merged stream
Then you can scan it. As docs says:
Rx.Observable.prototype.scan(accumulator, [seed])
Applies an accumulator function over an observable sequence and returns each
intermediate result.
That means you will be able to filter the list, storing the new list on the accumulator.
Once you subscribe, the data will be the new list.
people$.subscribe(data => console.log(data) ); //this will print your filtered list on console
Hope it helps/was clear enough
You can look how I did it here:
https://github.com/erykpiast/autocompleted-select/
It's end to end solution, with grabbing user interactions and rendering filtered list to DOM.
You could take a look at WebRx's List-Projections as well.
Live-Demo
Disclosure: I am the author of the Framework.

How can I add elements to a part of a json by using jquery

I try to add elements in a particular way to the following JSON:
var data = [{"name":"google",
"ip":"10.10.10.01",
"markets":[{"name":"spain","county":"6002,6017,6018,6019,6020"},
{"name":"france","county":"6003,6005,6006,6007,6008,6025,6026,6027,6028,6029"},
{"name":"japan","county":"6004,6021,6022,6023,6024"},
{"name":"korea","county":"6000,6013,6014,6015,6016"},
{"name":"vietnam","county":"6001,6009,6010,6011,6012"}]},
{"name":"amazon",
"ip":"10.10.10.02",
"markets":[{"name":"usa","county":"10000,10001,10002,10003,10004,10005"}]},
{"name":"yahoo",
"ip":"10.10.10.03",
"markets":[{"name":"japan","county":"10000"}]}];
I want to add this element to the json:
newData = [{"name":"amazon",
"ip":"10.10.10.02",
"markets":[{"name":"mexico","county":"9000"}]}];
The result might be exactly this:
var data = [{"name":"google",
"ip":"10.10.10.01",
"markets":[{"name":"spain","county":"6002,6017,6018,6019,6020"},
{"name":"france","county":"6003,6005,6006,6007,6008,6025,6026,6027,6028,6029"},
{"name":"japan","county":"6004,6021,6022,6023,6024"},
{"name":"korea","county":"6000,6013,6014,6015,6016"},
{"name":"vietnam","county":"6001,6009,6010,6011,6012"}]},
{"name":"amazon",
"ip":"10.10.10.02",
"markets":[{"name":"usa","county":"10000,10001,10002,10003,10004,10005"},
{"name":"mexico","county":"9000"}]},
{"name":"yahoo",
"ip":"10.10.10.03",
"markets":[{"name":"japan","county":"10000"}]}];
I tried to use :
$.extend(data.markets, newData)
$.extend(true, data, newData); //this works only in the case every element is new.
but nothing works the way I pretend.
Could anyone give me a solution?
Thanks in advance.
You haven't created JSON, you've created a JavaScript literal object.
You could add this particular piece of newdata by
data[1].markets.push({"name":"mexico","county":"9000"})
Because you are dealing with javascript objects, you can write a function to check for the existence of data[n] and push data.
You have an array of objects, where each object is like the following:
var item = {"name":"...",
"ip":"...",
"markets":[ /*some objects here*/];
}
So why not just creating your custom method to insert elements? It could search in the array if an item with the same name and ip exists, and then:
If it does exist: append the markets to the existing item markets attribute (maybe you need to check again if they already exist). UPDATE:The code that #jasonscript added in his answer will do the job: once you have found where to add the market, just add it to the array. Again, maybe you'll have to check if that market was already in the array. Using jQuery it will be: $.extend(true, data[i],newData)
If it doesn't exist: just add the item to the array: $.extend(true, data,newData)
Stealing a little code from another answer:
$.each(data, function(item){
if(item.name == newData[0].name && item.ip == newData[0].ip) {
item.markets.push.apply(item.markets, newData[0].markets);
}
}
This assumes that you know that all the market items in the new object are different to the existing ones - otherwise you'd have to do a nested foreach or something. If you can change the notation of the objects a little you could think about using a dictionary-like object for Markets to make that a little cleaner.
In fact, changing data from an associative array would probably work for that too. Then you could easily check for existence with:
if(data[myNewDataName]){
//add to markets
} else {
data[myNewDataName] = myNewData;
}

Javascript pushing objects into array changes entire array

I'm using a specific game making framework but I think the question applies to javascript
I was trying to make a narration script so the player can see "The orc hits you." at the bottom of his screen. I wanted to show the last 4 messages at one time and possibly allow the player to look back to see 30-50 messages in a log if they want. To do this I set up and object and an array to push the objects into.
So I set up some variables like this initially...
servermessage: {"color1":"yellow", "color2":"white", "message1":"", "message2":""},
servermessagelist: new Array(),
and when I use this command (below) multiple times with different data called by an event by manipulating servermessage.color1 ... .message1 etc...
servermessagelist.push(servermessage)
it overwrites the entire array with copies of that data... any idea why or what I can do about it.
So if I push color1 "RED" and message1 "Rover".. the data is correct then if I push
color1"yellow" and message1 "Bus" the data is two copies of .color1:"yellow" .message1:"Bus"
When you push servermessage into servermessagelist you're really (more or less) pushing a reference to that object. So any changes made to servermessage are reflected everywhere you have a reference to it. It sounds like what you want to do is push a clone of the object into the list.
Declare a function as follows:
function cloneMessage(servermessage) {
var clone ={};
for( var key in servermessage ){
if(servermessage.hasOwnProperty(key)) //ensure not adding inherited props
clone[key]=servermessage[key];
}
return clone;
}
Then everytime you want to push a message into the list do:
servermessagelist.push( cloneMessage(servermessage) );
When you add the object to the array, it's only a reference to the object that is added. The object is not copied by adding it to the array. So, when you later change the object and add it to the array again, you just have an array with several references to the same object.
Create a new object for each addition to the array:
servermessage = {"color1":"yellow", "color2":"white", "message1":"", "message2":""};
servermessagelist.push(servermessage);
servermessage = {"color1":"green", "color2":"red", "message1":"", "message2":"nice work"};
servermessagelist.push(servermessage);
There are two ways to use deep copy the object before pushing it into the array.
1. create new object by object method and then push it.
servermessagelist = [];
servermessagelist.push(Object.assign({}, servermessage));
Create an new reference of object by JSON stringigy method and push it with parse method.
servermessagelist = [];
servermessagelist.push(JSON.parse(JSON.stringify(servermessage));
This method is useful for nested objects.
servermessagelist: new Array() empties the array every time it's executed. Only execute that code once when you originally initialize the array.
I also had same issue. I had bit complex object that I was pushing in to the array. What I did; I Convert JSON object as String using JSON.stringify() and push in to the Array.
When it is returning from the array I just convert that String to JSON object using JSON.parse().
This is working fine for me though it is bit far more round solution.
Post here If you guys having alternative options
I do not know why a JSON way of doing this has not been suggested yet.
You can first stringify the object and then parse it again to get a copy of the object.
let uniqueArr = [];
let referencesArr = [];
let obj = {a: 1, b:2};
uniqueArr.push(JSON.parse(JSON.stringify(obj)));
referencesArr.push(obj);
obj.a = 3;
obj.c = 5;
uniqueArr.push(JSON.parse(JSON.stringify(obj)));
referencesArr.push(obj);
//You can see the differences in the console logs
console.log(uniqueArr);
console.log(referencesArr);
This solution also work on the object containing nested keys.
Before pushing, stringify the obj by
JSON.stringify(obj)
And when you are using, parse by
JSON.parse(obj);
As mentioned multiple times above, the easiest way of doing this would be making it a string and converting it back to JSON Object.
this.<JSONObjectArray>.push(JSON.parse(JSON.stringify(<JSONObject>)));
Works like a charm.

Categories

Resources