I have an array of objects, which contains more array of objects (with the same structure) with unknown depth.
sTree = [{
Tree: [{
Tree: [{
}],
Leafs:[{},{},{}]
}],
Leafs:[{},{},{}]
}
it's a classic (and actual) tree.
Each Object has a reference in a DOM object (using $(obj).data("ref",obj)).
|this part is done|
The UI is flagging some of the objects with obj.deleted = true.
|this part is done|
When the user is done, i want to get back the sTree, without the deleted=true flagged items.
How can it be done?
thanks
Do it with recursion. Loop over the structure and check every item like this:
function cleanTree(tree){
for(var i in tree){
if(tree[i].deleted){
// debug output
console.log('delete '+tree[i].toString());
delete tree[i];
}else{
// debug output
console.log('look at '+tree[i].toString());
tree[i] = cleanTree(tree[i]);
}
}
return tree;
}
You have to change the inside of the for-loop a bit to work with your structure.
Related
I have this object structure that I want to iterate through to make a node of all the "properties." So I want to make nodes for the objects 1,2,5, and 8 but not for the arrays. I have this piece of code and was wondering why Object.keys() for each of response's properties is [0] instead of [2,5] or [9,12]?
const response = {
'1':{
'2':['3','4'],
'5':['6','7']
},
'8':{
'9':['10','11'],
'12':['13','14']
},
};
for(const property in response){
if(!response.hasOwnProperty(property)) continue;
console.log(property) // prints 1 and 8
g.addNode(property);
console.log(Object.keys(property)) // [0] instead of [2,5] or [9,12]
for(const prop in property){
if(!property.hasOwnProperty(prop) || prop === 0) continue;
console.log(prop)
g.addEdge(prop,property, {directed:true})
}
}
EDIT: this loop works :)
for(const property in resp){
g.addNode(property);
for(const prop in resp[property]){
g.addEdge(property,prop, {directed:true})
}
}
I've run into this exact issue with dictionaries, and it's good you're running into this issue relatively quickly because it can get pretty hard to debug once you get further. Basically, you're iterating over a dictionary with a for..in loop, which doesn't exactly do what you want it to. Basically, each item you iterate over (property in this case) isn't the value of the dictionary ({'2':['3','4'], '5':['6','7']}), it's a full dictionary item that includes both key and value. This is practically useless to you, so it's not particularly helpful. There are a couple things you can do, one of which still uses a forEach, except somewhat differently:
Object.keys(response).forEach(function(key) {
// do your actions here
// key is your dictionary key (1, 8)
// response[key] will have your value ({'2':['3','4'], '5':['6','7']})
});
This should work, and you can put the rest of your code to use this.
I have a very large JSON feed of events that I am pulling into JavaScript via AJAX. Once I have the object in memory, I want to just be able to use that instead of making a new AJAX call each time.
I have a form that allows the JSON events to be filtered. Upon initial filter, my function duplicates the original object (to preserve it), then deletes keys from the new object when they don't match the filter criteria.
This works perfectly the first time the set of functions is run. However, when run again, it appears that the original object is being altered which then triggers a JavaScript error.
When I console.debug the original object, I can see that the first time it runs, it is an object as expected. On further runs, it looks like it's being converted into an array of objects somehow.
I have simplified the code to show the issue here:
json = [{"title": "Title 1","time": 1},{"title": "Title 2","time": 1},{"title": "Title 3","time": 2},{"title": "Title 4","time": 2},{"title": "Title 5","time": 3},{"title": "Title 6","time": 3},{"title": "Title 7","time": 4},{"title": "Title 8","time": 4},{"title": "Title 9","time": 5},{"title": "Title 10","time": 5}];
jQuery('a').on('click touch tap', function(){
propEvents(json);
return false;
});
//End prep code for example
function propEvents(json){
var loadFromMemory = 0;
if ( loadFromMemory == 0 ){
globalEventObject = json;
loadFromMemory = 1;
}
console.log('Initial Global Object:');
console.debug(globalEventObject);
//Filter the JSON
filteredEventsObject = eventSearch(globalEventObject);
//The global object was never filtered, but keys are being removed from it too... I need to store it in memory to start filters from scratch each time.
console.log('Global Object After Filter:');
console.debug(globalEventObject);
}
function eventSearch(events){
var tempObject = events; //May be unnecessary, but for example purposes.
jQuery(tempObject).each(function(i){
if ( tempObject[i].time != 3 ){
console.log('no match: removing this event');
delete tempObject[i]; //Remove this key from the tempObject
return;
}
});
tempObject = tempObject.filter(function(){return true;}); //Start the keys from 0 again.
console.log('Length of filtered object:');
console.debug(tempObject.length);
return tempObject;
}
Here it is in CodePen where you can view the console logs. This has me spinning my wheels for a few days now and I just can't wrap my head around it. Any clues would be appreciated.
The line var tempObject = events; doesn't actually clone the object. Instead, it makes a var tempObject point to events, and subsequently, any side effects you have on tempObject also happen on events.
There are plenty of ways to clone objects, see this SO question for details: What is the most efficient way to deep clone an object in JavaScript?
Since you mention you're trying to manipulate a JSON feed, I would suggest
var clone = JSON.parse(JSON.stringify(events))
and manipulaing clone.
JavaScript passes objects as a copy of reference. Follow this post for further details.
StackOverflow
i have one array of ids and one JavaScript objects array. I need to filter/search the JavaScript objects array with the values in the array in Node JS.
For example
var id = [1,2,3];
var fullData = [
{id:1, name: "test1"}
,{id:2, name: "test2"}
,{id:3, name: "test3"}
,{id:4, name: "test4"}
,{id:5, name: "test5"}
];
Using the above data, as a result i need to have :
var result = [
{id:1, name: "test1"}
,{id:2, name: "test2"}
,{id:3, name: "test3"}
];
I know i can loop through both and check for matching ids. But is this the only way to do it or there is more simple and resource friendly solution.
The amount of data which will be compared is about 30-40k rows.
This will do the trick, using Array.prototype.filter:
var result = fullData.filter(function(item){ // Filter fulldata on...
return id.indexOf(item.id) !== -1; // Whether or not the current item's `id`
}); // is found in the `id` array.
Please note that this filter function is not available on IE 8 or lower, but the MDN has a polyfill available.
As long as you're starting with an unsorted Array of all possible Objects, there's no way around iterating through it. #Cerbrus' answer is one good way of doing this, with Array.prototype.filter, but you could also use loops.
But do you really need to start with an unsorted Array of all possible Objects?
For example, is it possible to filter these objects out before they ever get into the Array? Maybe you could apply your test when you're first building the Array, so that objects which fail the test never even become part of it. That would be more resource-friendly, and if it makes sense for your particular app, then it might even be simpler.
function insertItemIfPass(theArray, theItem, theTest) {
if (theTest(theItem)) {
theArray.push(theItem);
}
}
// Insert your items by using insertItemIfPass
var i;
for (i = 0; i < theArray.length; i += 1) {
doSomething(theArray[i]);
}
Alternatively, could you use a data structure that keeps track of whether an object passes the test? The simplest way to do this, if you absolutely must use an Array, would be to also keep an index to it. When you add your objects to the Array, you apply the test: if an object passes, then its position in the Array gets put into the index. Then, when you need to get objects out of the Array, you can consult the index: that way, you don't waste time going through the Array when you don't need to touch most of the objects in the first place. If you have several different tests, then you could keep several different indexes, one for each test. This takes a little more memory, but it can save a lot of time.
function insertItem(theArray, theItem, theTest, theIndex) {
theArray.push(theItem);
if (theTest(theItem)) {
theIndex.push(theArray.length - 1);
}
}
// Insert your items using insertItem, which also builds the index
var i;
for (i = 0; i < theIndex.length; i += 1) {
doSomething(theArray[theIndex[i]]);
}
Could you sort the Array so that the test can short-circuit? Imagine a setup where you've got your array set up so that everything which passes the test comes first. That way, as soon as you hit your first item that fails, you know that all of the remaining items will fail. Then you can stop your loop right away, since you know there aren't any more "good" items.
// Insert your items, keeping items which pass theTest before items which don't
var i = 0;
while (i < theArray.length) {
if (!theTest(theArray[i])) {
break;
}
doSomething(theArray[i]);
i += 1;
}
The bottom line is that this isn't so much a language question as an algorithms question. It doesn't sound like your current data structure -an unsorted Array of all possible items- is well-suited for your particular problem. Depending on what else the application needs to do, it might make more sense to use another data structure entirely, or to augment the existing structure with indexes. Either way, if it's planned carefully, will save you some time.
I want to create a diagram with d3.js using the tree layout. Instead of the common flare json structure with hierarchical children like:
{
"name":"bla",
"children":[
{
"name":"bla2",
"someattribute":"green"
}
]
}
I just have an array (of elements which represent a timestep). I always want the next element(s) of the array to be the child(ren) element of the current.
So in fact I want a tree to be generated out of a flattened array.
My idea was to change the children function of the tree layout like this:
var tree = d3.layout.tree()
.children(function(d,i) {
return data[(i+1)];
})
But only one element is displayed in the tree. I don't get it. Shouldn't it iterate over every element when calling tree.nodes on data[0] ?
To clarify my request: I want to turn an array like [ele1, ele2, ele3] into a tree graph that looks like:
ele1-->ele2-->ele3
The real issue I see is that the function passed to .children() needs to return an Array of children Objects, instead of a single Object as it is now, i.e.
var tree = d3.layout.tree()
.children(function(d,i) {
return i < data.length - 1; data.slice(i+1, i+2) : null;
})
It's also important that the leaf node (the last data Object in the array) returns null instead of an empty list.
Using this approach, I created a working JSFiddle that will create a linear tree from an array of objects.
However, I agree with #LarsKotthoff's comment on your post; your code would be better served in terms maintainability and flexibility if you passed tree.nodes() a root of an Object in hierarchical format.
In my node REST application I have a function that queries a database for several records and returns an array of objects.
Since I want it to return a JSON object, I need a way to convert the array of objects to a single object with all the records inside.
Unfortunately I can't find an example on the internet about doing something like this.
Any help would be appreciated.
Why would you want to do that ? Its totally fine to JSON stringify an Array of items, you'll get a structure like
"[{},{},{},...]"
that is probably even an advantage, because you keep the order of items guaranteed.
See the object function of underscore.js.
Lets assume you have an array of objects with the form:
log {
name: "foo",
log: "bar"
}
Your could do:
var logs,//Array of logs
logObj = {}
for(i=0, i<logs.Length i++) {
logObj[logs[i].Name] = logs[i].log;
}
After the loop logObj should be:
logObj {
foo: bar,
nextName: cool comment,
etc.
}