JS - add multiple dict values into a dict key - javascript

I have a dictionary as as shown below. I am trying to add dict values into them. This is what it stars with
var animals = {
flying : {},
underground : {},
aquatic : {},
desert : {}
};
For example: If I wanted to add d = {dove : [<some list>] } into animal[flying], how would i do it? I cannot enter the values manually as thus i am running a loop, I am able to write it manually, but not with program.
I have tried animals[flying] = d, this would work for the first time, but when i try to add another value it would be replaced and not appended.
In the end I am looking for something like this: This is what it ends with
var animals = {
flying : {
dove : [<list>],
sparrow : [<list>],
},
underground : {
rabbits : [<list>],
squirrel : [Squirrel],
},
aquatic : {
dolphin : [<list>],
whale : [Squirrel],
},
desert : {
camel : [<list>],
antelope : [<list>],
},
};

well because
myDict[subcat] = x
assigns it. You're working with lists. Think about it - when have you ever added an item to a list this way? Of course that overwrites your previous entry. What you want instead is to push the variable into the array (also, this isn't python. Lists are called Arrays and Dictionaries are called Objects. There is a distinction, but that's beyond the scope of an answer here. Google it).
So do this:
myDict = {
subCat: [],
}
And then when you loop:
myDict[subCat].push(x)

I think what you want to do is:
animals["flying"] = Object.assign(animals["flying"], d);
E.g.
animals = {
flying: {}
}
d = { dove: [1, 2, 3] }
Object.assign(animals["flying"], d);
d = { sparrow: [1, 2, 3] }
Object.assign(animals["flying"], d);
console.log(animals); //{"flying":{"dove":[1,2,3],"sparrow":[1,2,3]}}

var newAnimal = {name: 'bird'};
if(animals['flying']['dove'] && animals['flying']['dove'].length > 0) {
//List already exists so add the new animal
//TODO also check if the animal is already in the list?
animals['flying']['dove'].push(newAnimal);
}else {
//Create the new list
animals['flying']['dove'] = [newAnimal];
}

Related

How can I reformat this simple JSON so it doesn't catch "Circular structure to JSON" exception?

Introduction
I'm learning JavaScript on my own and JSON its something along the path. I'm working on a JavaScript WebScraper and I want, for now, load my results in JSON format.
I know I can use data base, server-client stuff, etc to work with data. But I want to take this approach as learning JSON and how to parse/create/format it's my main goal for today.
Explaining variables
As you may have guessed the data stored in the fore mentioned variables comes from an html file. So an example of the content in:
users[] -> "Egypt"
GDP[] -> "<td> $2,971</td>"
Regions[] -> "<td> Egypt </td>"
Align[] -> "<td> Eastern Bloc </td>"
Code
let countries = [];
for(let i = 0; i < users.length; i++)
{
countries.push( {
'country' : [{
'name' : users[i],
'GDP' : GDP[i],
'Region' : regions[i],
'Align' : align[i]
}]})
};
let obj_data = JSON.stringify(countries, null, 2);
fs.writeFileSync('countryballs.json', obj_data);
Code explanation
I have previously loaded into arrays (users, GDP, regionsm align) those store the data (String format) I had extracted from a website.
My idea was to then "dump" it into an object with which the stringify() function format would format it into JSON.
I have tested it without the loop (static data just for testing) and it works.
Type of error
let obj_data = JSON.stringify(countries, null, 2);
^
TypeError: Converting circular structure to JSON
--> starting at object with constructor 'Node'
| property 'children' -> object with constructor 'Array'
| index 0 -> object with constructor 'Node'
--- property 'parent' closes the circle
What I want from this question
I want to know what makes this JSON format "Circular" and how to make this code work for my goals.
Notes
I am working with Node.js and Visual Studio Code
EDIT
This is further explanation for those who were interested and thought it was not a good question.
Test code that works
let countries;
console.log(users.length)
for(let i = 0; i < users.length; i++)
{
countries = {
country : [
{
"name" : 'CountryTest'
}
]
}
};
let obj_data = JSON.stringify(countries, null, 2);
fs.writeFileSync('countryballs.json', obj_data);
});
Notice in comparison to the previous code, right now I am inputing "manually" the name of the country object.
This way absolutely works as you can see below:
Now, if I change 'CountryTest' to into a users[i] where I store country names (Forget about why countries are tagged users, it is out of the scope of this question)
It shows me the previous circular error.
A "Partial Solution" for this was to add +"" which, as I said, partially solved the problem as now there is not "Circular Error"
Example:
for(let i = 0; i < users.length; i++)
{
countries = {
country : [
{
"name" : users[i]+''
}
]
}
};
Resulting in:
Another bug, which I do not know why is that only shows 1 country when there are 32 in the array users[]
This makes me think that the answers provided are not correct so far.
Desired JSON format
{
"countries": {
"country": [
{
"name": "",
"GDP" : "",
"Region" : "",
"Align" : ""
},
{
"name": "",
"GDP" : "",
"Region" : "",
"Align" : ""
},
{
"name": "",
"GDP" : "",
"Region" : "",
"Align" : ""
}
]}
}
Circular structure error occurs when you have a property of the object which is the object itself directly (a -> a) or indirectly (a -> b -> a).
To avoid the error message, tell JSON.stringify what to do when it encounters a circular reference. For example, if you have a person pointing to another person ("parent"), which may (or may not) point to the original person, do the following:
JSON.stringify( that.person, function( key, value) {
if( key == 'parent') { return value.id;}
else {return value;}
})
The second parameter to stringify is a filter function. Here it simply converts the referred object to its ID, but you are free to do whatever you like to break the circular reference.
You can test the above code with the following:
function Person( params) {
this.id = params['id'];
this.name = params['name'];
this.father = null;
this.fingers = [];
// etc.
}
var me = new Person({ id: 1, name: 'Luke'});
var him = new Person( { id:2, name: 'Darth Vader'});
me.father = him;
JSON.stringify(me); // so far so good
him.father = me; // time travel assumed :-)
JSON.stringify(me); // "TypeError: Converting circular structure to JSON"
// But this should do the job:
JSON.stringify(me, function( key, value) {
if(key == 'father') {
return value.id;
} else {
return value;
};
})
The answer is from StackOverflow question,
Stringify (convert to JSON) a JavaScript object with circular reference
From your output, it looks as though users is a list of DOM nodes. Rather than referring to these directly (where there are all sort of possible cyclical structures), if you just want their text, instead of using users directly, try something like
country : [
{
"name" : users[i].textContent // maybe also followed by `.trim()
}
]
Or you could do this up front to your whole list:
const usersText = [...users].map(node => node.textContent)
and then use usersText in place of users as you build your object.
If GDP, regions and align are also references to your HTML, then you might have to do the same with them.
EUREKA!
As some of you have mentioned above, let me tell you it is not a problem of circularity, at first..., in the JSON design. It is an error of the data itself.
When I scraped the data it came in html format i.e <td>whatever</td>, I did not care about that as I could simply take it away later. I was way too focused in having the JSON well formatted and learning.
As #VLAZ and #Scott Sauyezt mentioned above, it could be that some of the data, if it is not well formatted into string, it might be referring to itself somehow as so I started to work on that.
Lets have a look at this assumption...
To extract the data I used the cheerio.js which gives you a kind of jquery thing to parse html.
To extract the name of the country I used:
nullTest = ($('table').eq(2).find('tr').eq(i).find('td').find('a').last());
//"Partial solution" for the OutOfIndex nulls
if (nullTest != null)
{
users.push(nullTest);
}
(nullTest helps me avoid nulls, I will implement some RegEx when everything works to polish the code a bit)
This "query" would output me something like:
whatEverIsInHereIfThereIsAny
or else.
to get rid off this html thing just add .html() at the end of the "jquery" such as:
($('table').eq(2).find('tr').eq(i).find('td').find('a').last().html());
That way you are now working with String and avoiding any error and thus solves this question.

Javascript - How to define Arrays inside an Object using Loops?

I'm trying to make a Pixel RPG game, and am a bit confused.
What I'm trying to do:
var character = {
gender: male,
age: 18,
action: walking,
direction: left,
skin: 0,
eyes: aqua,
hairStyle: 0,
hairColor: blue,
hat: 'cap'
};
ctx.drawImage(characterIMG.body[character.gender][character.skinColor], 0, 0);
ctx.drawImage(characterIMG.eyes[character.gender][character, 0, 0);
ctx.drawImage(characterIMG.hair[style0], 0, 0);
if(character.hat != "none"){
ctx.drawImage(characterIMG.hat['cap'], 0, 0);
}
How would I go about defining the images?
So far got here, but am mixed up..
var characterIMG = [male, female]; //I want some separate variables to just write in, in case I need to add more images of the same type, then I can just write the "type" in the variable instead of changing a bunch of stuff :)
for(var i in characterIMG){
characterIMG[i] = {
skin: [],
eyes: [],
hair: [],
accessories: []
}
}
Unless there is a more efficient way to do this?
Thanks!
--In short, I want to do this:
ctx.drawImage(characterIMG.body[character.gender][character.skinColor], 0, 0);
ctx.drawImage(characterIMG.eyes[character.gender][character], 0, 0);
ctx.drawImage(characterIMG.hair[style0], 0, 0);
..with characterIMG containing a huge database of all the relevant images (this)
Use an object and then just new up the object whenever you want to create a new instance of a character. With this, each character can inherit their properties from the main Object (via prototype) and become a separate entity within your game.
var Person = function(payload) {
this.name = payload.name;
this.age = payload.age;
this.gender = payload.gender;
};
Person.prototype.talk = function() {
return console.log('hello, I am ' + this.name);
}
var Person1 = new Person({
name : 'Amanda',
age : 18,
gender : 'Female',
});
var Person2 = new Person({
name : 'Sam',
age : 21,
gender : 'Make',
});
Person1.talk();
Person2.talk();
You can load a set of images as follows
// a list of image name comma delimited
const imageURLs = "image1.jpg,image2.jpg,image3.jpg";
// create an array of images
const myImageList = imageURLs.split(",").map(url => {
const image = new Image;
image.src = url;
return image;
});
If you have many images with different categories and subcategories then it will depend on how you organise the images on your file system. If you have one directory and all the images in that then each image's name should have some description of the image
body_dark_female.jpg
body_light_female.jpg
body_dark_male.jpg
body_light_male.jpg
head_dark_female.jpg
head_light_female.jpg
head_dark_male.jpg
head_light_male.jpg
And so on, or a better option is to set the various categories in directories
body/dark/female/jill.jpg
body/dark/male/tom.jpg
body/light/female/jill.jpg
body/light/male/tom.jpg
head/light/female/jill.jpg
head/light/male/tom.jpg
head/dark/female/jill.jpg
head/dark/male/tom.jpg
You can then use the name or directories to create the data structure
// using the directory structure
function loadImage(imageURL,images){
const cats = imageURL.split("/"); // split the cats into an array
// remove the last item as that is the image name
var name = cats.pop();
// remove the extension and add just the image name to the cats
cats.push(name.split(".")[0]);
// reference the base category
var currentCat = images;
cats.forEach(cat => { // for each category create the objects
if(currentCat[cat] === undefined){ // does this cat exist?
currentCat[cat] = {}; // no them create an object for it
}
currentCat = currentCat[cat]; // reference the category
});
// now create the image and add it to the object
currentCat = new Image;
currentCat.src = imageURL;
}
Then use the directory listing to create the list of images to load
const imageURLs = `
body/dark/female/jill.jpg
body/dark/male/tom.jpg
body/light/female/jill.jpg
body/light/male/tom.jpg
head/light/female/jill.jpg
head/light/male/tom.jpg
head/dark/female/jill.jpg
head/dark/male/tom.jpg
`;
Because the directory listing may be a bit unclean (spaces, tabs, linefeeds, etc) you should ensure each image name is valid
// remove tabs, groups of spaces and returns, and use linefeed to seperate them
const imagesURLClean = imageURLs.replace(/\t|\r| +?/g,"").split("\n");
// create the base category
const characterIMG = {};
// add the images
imagesURLClean.forEach(imageURL => loadImage(imageURL,characterIMG));
When that has run you can access the image as follows
ctx.drawImage(characterIMG.body.light.female.jill,0,0);
Or via strings
var part = "body";
var skin = "light";
var gender = "female";
var name = "jill";
ctx.drawImage(characterIMG[part][skin][gender][name],0,0);
The directory listing will create the following data structure
characterIMG = {
body : {
dark : {
female : {
jill : // the image
},
male : {
tom : // the image
},
},
light : {
female : {
jill : // the image
},
male : {
tom : // the image
},
}
},
head : {
dark : {
female : {
jill : // the image
},
male : {
tom : // the image
},
},
light : {
female : {
jill : // the image
},
male : {
tom : // the image
},
}
}
If your list is very long it may have missing items, during development it would pay to add a default category that will return an image appropriate for that category.
Thus you directory listing would look like
body/default.jpg // default
body/light/default.jpg // default
body/light/female/default.jpg // default
body/light/male/default.jpg // default
body/dark/default.jpg // default
body/dark/female/default.jpg // default
body/dark/female/jill.jpg
body/dark/male/default.jpg // default
body/dark/male/tom.jpg
// and so on
Then create a function that gets a image via category and if it has problems it will use the default image as far as it can find to fit the categories
function getImage(images, ...categories){
const count = 0;
var image = images
while(count < categories.length){
if(image[categories[count]] !== undefined){
image = image[categories[count++]];
}else{
return image.default;
}
}
return image;
}
Then you can draw an image as follows
ctx.drawImage(getImage(characterIMG,"body","dark","female","jill"),0,0);
// when you get the wrong referance
ctx.drawImage(getImage(characterIMG,"leg","dark","female","jill"),0,0);
// it will return characterIMG.default
// or
ctx.drawImage(getImage(characterIMG,"body","dark","female","bill"),0,0);
// as there is no female bill, it will return characterIMG.body.dark.female.default
This is how you define an array inside an object.
var characterIMG = {
male: {
skins: [],
hair: ["black", "brown"]
},
female: {
skins: [],
hair: []
}
};
console.log(characterIMG);
console.log(characterIMG["male"]["hair"]);
console.log(characterIMG.male.hair); //does the same

Issue Pushing values in to objects Javascript

Have some issue with push the values in to the javascript array object. Please any one give me the perfect solution
Class code :
var myfuns = ( function(undefined) {
var myarr ={};
function _add(arrayparam){
if (myarr.current == undefined) {
myarr.current = [];
myarr.current.push(options.current_info);
}else{
}
}
function _getList() {
return $.extend(true, {}, myarr);
}
return {
add : _add,
getList : _getList
}
}());
Here am calling and manage the values and keys
function setmydetails(){
var my_param = {
current_info : {
pg : '#tset',
no : 12,
name : "john",
row : 0,
},
userprofile : [],
class : [],
marks : [],
games : []
};
myfuns.add(my_param);
}
Now i got the array
myfuns.getList() // GOT proper array what i passed in my_param
Question : How to modify the existing values from any one of the Inner array from the myarr Obj
Ex: Once First array created later have to modify some from "myarr.current" = > Change current_info.row to 2222
Similar i have to add some array in to " myarr.class " etc
I would like to say try this one not tested
function _add(arrayparam){
if (myarr.current == undefined) {
myarr.current = [];
myarr.current.push(options.current_info);
}else{
$.extend( myarr.current, arrayparam);
}
}
proper source : https://api.jquery.com/jquery.extend/

Optimize comparing huge amounts of data with itself in NodeJS

I have a big multidimensional object in nodejs, say 50 MB worth of JSON. It contains variations of biological data. I think I can sufficiently simplify it like so:
{
lads : {
// a lad
lad4515643 : {
brains : {
// a brain
brain1256251 : {
var01 : 'lala',
var02 : 'jaja',
var99 : 'haha',
},
// another brain
brain3567432 : {},
brain4867321 : {},
brain5145621 : {} // etc
},
var01 : 'foo',
var02 : 'bar',
var99 : 'baz'
},
// another lad
lad4555672 : {},
lad5625627 : {},
lad7457255 : {} // etc
}
}
I need to compare all combinations of lads with brains to all lads with brains to see which ones are "better", in order to make some kind of hierarchy. Some parent lads keys weigh in on the brains comparison.
I figured, using iterations over objects using references we can easily assign IDs of the better ones. Take a quick glance over the code (comments) and you see what I mean:
// Iterate over lads
for (var ladId in obj.lads) {
if (obj.lads.hasOwnProperty(ladId)) {
var lad = obj.lads[ladId];
// Iterate over brains
for (var brainId in lad.brains) {
if (lad.brains.hasOwnProperty(brainId)) {
var brain = lad.brains[brainId];
// Iterate over lads again
for (var lad2Id in obj.lads) {
if (obj.lads.hasOwnProperty(lad2Id)) {
var lad2 = obj.lads[lad2Id];
// Iterate over this lads' brains
for (var brain2Id in lad2.brains) {
if (lad2.brains.hasOwnProperty(brain2Id)) {
var brain2 = lad2.brains[brain2Id];
// One lad+brain combination
var drone1 = {
lad : lad,
brain : brain
};
// Another lad+brain combination
var drone2 = {
lad : lad2,
brain : brain2
ladId : lad2Id, // Required to store the reference if better
brainId : brain2Id // Required to store the reference if better
};
// Do the comparison unless we are comparing ourselves
if (brain != brain2) {
// Objects are passed as reference, so this is convenient:
judge(drone1, drone2);
}
}
}
}
}
}
}
}
}
// Judge who is better
function judge(drone1, drone2) {
// some magic that compares lad+brain combos
if (magic) {
// Add list of better versions
drone1.brain.better = drone1.brain.better || [];
// Everything is passed by reference - I can modify the original brain object directly
drone1.brain.better.push({
ladId : drone2.ladId,
brainId : drone2.brainId
});
}
}
Now of course, the number of iterations increases exponentially when the dataset increases. With 3000 brains in total, there are already 9 million iterations, which with the magic adds up to more than 10 seconds of execution time.
What optimizations would be (hugely) beneficial in a scenario like this, apart from using multiple threads?
Since judge() is purely math, does it really make a difference if I convert every single step of the iteration to a callback style? (In my imagination, that would only create a huge overhead of anonymous functions and memory usage.)

Dynamically adding members to a javascript object

I'm working on a scoring script for contract bridge, just for giggles. I'm storing the game as an object:
var game = {
team1 : { player1 : prompt("Team 1, first player: "), player2 : prompt("Team 1, second player:") },
team2 : { player1 : prompt("Team 2, first player: "), player2 : prompt("Team 2, second player:") },
}
function deal(bid){
console.log("The bid was " + bid);
game.hand = {"bid" : bid , "made" : undefined};
score();
}
So what I'd like to do though, better than this, is to keep a history of the games played this session. I'd like to, in pseudocode, do something like this:
game.(hand + (hand.length+1))
or something kind of like that; basically auto-increment a certain object within an object. I'm not so sure an array would would here, but perhaps? I'm open to suggestions/bettering of my code.
PS - I'd prefer to do this in javascript, not jQuery, Prototype, Dojo, MooTools... or any other library. Thanks!
EDIT
Sorry, let me clarify: The result after playing 3 hands or so would be an object like this:
var game = {
team1 : { player1 : prompt("Team 1, first player: "), player2 : prompt("Team 1, second player:") },
team2 : { player1 : prompt("Team 2, first player: "), player2 : prompt("Team 2, second player:") },
hand1 : { bid : 2 , made : 2 } ,
hand2 : { bid : 1 , made : 4 } ,
hand3 : { bid : 3 , made : 1 } ,
hand4 : { bid : 2 , //and made hasn't been set yet because we're mid-hand
}
Given your pseudocode, you can do the following:
game[hand + (hand.length+1)]
i.e. game["prop"] == game.prop - both provide access to the same property.
Old question, I see but I have a need to do something similar. I'd vote up the answer but I'm not allowed.
It appears the fastest way to do this is to access the object like a hash / associative array.
var d = {};
var z = "hand";
d[z+1] = "foo";
console.log(d.hand1);
Test this out in firebug. Seems to work pretty well.
JS does not seem to have an php equivalent to force resolution of the variables as in the curley braces around an expression.
d->{z+1} = "foo"; // can't find anything like this in JS.
Hope that helps,

Categories

Resources