can't iterate over map containing objects from custom class - javascript

I have a map that I created to store several instances of a custom class I wrote. If I do a simple console.log(myMapName), I see the details in the output. I see the six entries in my map, I see the key values I stored them under, and then for each entry, I can expand it and see the internals of that instance of my custom class, including the stored values for each attribute in that class definition.
But if I try to use for(let[key,value] of myMapName) to loop over the instances of my class stored as entries in my map and write the key and value of each one to the console using console.log, I see nothing. I can't even get it to at least log the key value for each entry. I would not be surprised if I was doing something wrong to cause it not to log the details of the value of each entry, but the fact that it also refuses to at least list the key value stumps me.
I should mention that I am able to loop over a small test map I created and get the key and value output in the log. Shown here below:
// test map definition
let myMap = new Map();
myMap.set('First',{name: 'John', age: '34'})
myMap.set('Second',{name: 'Mary', age: '24'})
// I can loop over this simple map
console.log(myMap)
for(let [key,value] of myMap){
console.log('key: ' + key)
console.log('value.name: ' + value.name)
console.log('value.age: ' + value.age)
}
// log output for above
// but using the same loop structure for my map doesn't work
for(let [key,value] of mgroups){
console.log('key: ' + key)
console.log('value: ' + value)
console.log('value.name: ' + value.name)
}
Edit: adding my class' code and a pic of its log output. the loop code is shown already above:
class MaterialGroup {
constructor(name){
this.name = name;
this.alias = name;
this.usemtl = "";
this.faces = [];
this.indices = [];
this.vertices = [];
}
setName(name){ this.name = name; }
getName(){ return this.name; }
setGroupIndices(){}
getGroupIndices(){}
setGroupVertices(){}
getGroupVertices(){}
}
module.exports = MaterialGroup
Sample of log output of console.log(mgroups):
Edit#2: below is the function where I use node.js' fs module's readline to to read in a file and populate the instances of my custom class (shown above) and then add each to the mgroups map. This is done and completed before the attempt to loop mentioned in the question but might be where the async issue I am seeing is introduced. This method gets called to read in the data and populate the mgroups map and then right after that another method is called to loop over it.
function readObjFile(objFilePath){
var objInput = fs.createReadStream(objFilePath);
var rl = require('readline').createInterface({
input: objInput,
terminal: false
});
...
let mgroup = new MaterialGroup("NotSet");
rl.on('line', function(line){
var pieces = line.split(" ");
...
// section of function that works with MaterialGroup class that
// gets added to my mgroups map using .set calls
if(pieces[0] == "g"){
var mpieces = pieces[1].split("_");
if(processing == "mgroups"){
mgroups.set(mgroup.name, mgroup);
mgroup = new MaterialGroup(mpieces[mpieces.length - 1]);
} else {
processing = "mgroups";
mgroup = new MaterialGroup(mpieces[mpieces.length - 1]);
}
}
if(pieces[0] == "usemtl"){
mgroup.usemtl = pieces[1];
}
// this is new f block for material group faces
if(pieces[0] == "f"){
mgroup.faces.push([pieces[1]-1,pieces[2]-1,pieces[3]-1]);
mgroup.indices.push(pieces[1]-1);
mgroup.indices.push(pieces[2]-1);
mgroup.indices.push(pieces[3]-1);
mgroup.vertices.push(vertices[pieces[1]]);
mgroup.vertices.push(vertices[pieces[2]]);
mgroup.vertices.push(vertices[pieces[3]]);
indices.push(pieces[1]-1);
indices.push(pieces[2]-1);
indices.push(pieces[3]-1);
}
if(pieces[0] == "eof"){
mgroups.set(mgroup.name, mgroup);
}
}).on('close', () => {
...
setMgroupsMap(mgroups);
});
}
I can do a simple console.log(mgroups) and see all of the entries and their details but I can't loop over them one by one.
One thing that caught my attention is that even in the log where I can see the six entries and their details, it shows Map(0) at the top of that log entry. This makes no sense to me since in the details below the six entries I see the size entry for the map and there it shows a value of 6.
Does anyone know of a detail has to be addressed when attempting to loop over the entries of a map that are instances of a custom class definition? I think this is the root cause since the only other difference I notice between my output and a test output I did of a simple make using standard object entries like {'name':'John', 'age':'34'} (aside from the fact that this test map showed the correct size of Map(2) at the top of its log output) was that for my map it shows {"KeyValue" => MyCustomClassName} and the simple test map just shows {"KeyValue" => Object}.
I'm sure I'll get a lot of "this has been asked" quick replies, but I have looked at this from many angles and tried a lot of different ways to loop it and have gotten nowhere, and I have tried looking at many other posted questions but they did not help. So, thanks to anyone who takes the time to provide a helpful reply.

class Person {
constructor(name, age) {
this.name = name
this.age = age
}
}
let mgroups = new Map()
mgroups.set('First', new Person('John', '34'))
mgroups.set('Second', new Person('Mary', '24'))
for (let [ key, value ] of mgroups) {
console.log('key: ' + key)
console.log('value: ' + value)
console.log('value.name: ' + value.name)
console.log('value.age: ' + value.age)
}

Related

foreach Statements with a function

ok I am trying to answer a question and learning to code. regarding an array and using foreach statements the function must remain as this "function animalNames" must stay somewhere but apparently, I am doing something wrong because I get it returned as undefined. even through it produces the correct array back could someone look at it and let me know what i have done wrong.
attached is a picture of the code and array and question that i answered. this is how i wrote my function.
const displayNames = [];
zooAnimals.forEach(function animalNames(element){
var display = "name: " + element.animal_name + ", " + "scientific: " + element.scientific_name
displayNames.push(display);
})
console.log(displayNames);
again i get the correct array back and the data looks correct...but animalNames comes back as undefined...i cannot remove this portion i am to keep it there but i do not know what to do with it.
try this, it defines a function animalNames as separate function
const displayNames = [];
const zooAnimals = [
{animal_name:"Jackel",scientific_name:"Canine"}
]
function animalNames({animal_name, scientific_name}){
return `name: ${animal_name}, scientific: ${scientific_name}`
}
zooAnimals.forEach((element)=>{
displayNames.push(animalNames(element));
})
console.log(displayNames);
I believe you are following this challenge. In this case, make sure to read the instructions properly:
The zoos want to display both the scientific name and the animal name in front of the habitats.
Use animalNames to populate and return the displayNames array with only the animal name and scientific name of each animal.
displayNames will be an array of strings, and each string should follow this pattern: "name: {name}, scientific: {scientific name}"
So from the instructions you are expected to create a function animalNames() that creates an array named displayNames and returns this array from within your function animalNames(). The array displayNames contains strings of the sturcture name: animal_name, scientific: scientific_name.
// you could set zooAnimals as a required parameter in your function
// but as it is defined in the same file you can access it directly as well
function animalNames() {
const displayNames = [];
// you have to do the forEach on zooAnimals here
zooAnimals.forEach(animal => displayNames.push(`name: ${animal.animal_name}, scientific: ${animal.scientific_name}`))
// return an array
return displayNames;
}
The way you did it, the function animalsName() is an anonymous function that only exists within the zooAnimals.forEach() call. Therefore, it is undefined.

Map.delete() not working on key in parent Map

What I'm doing right now, is deleting any diff that doesn't contain the string, and if the diff's dictionary is empty, then i try to delete the map.
the issue here is that, i can't delete a map with data.delete(map) for some reasons (no errors in console) and any piece of code located after that deletion in the if statement won't run.
here is the code in question:
var data = new Map({"593620 Linked Horizon - Shinzou o Sasageyo! [TV Size]": {"difficulties": {"Titan": 86813}}, "859608 LiSA - ADAMAS (TV Size)": {"difficulties": {"Kibbleru's Blue Rose": 899}},"940746 CHiCO with HoneyWorks - Kimi ga Sora Koso Kanashikere": {"difficulties": {"Taeyang's Extra": 72321}}});
var string = "titan";
Array.from(data.keys()).forEach(function(map) {
if (!(map.toLowerCase().indexOf(string.toLowerCase()) >=0)) {
if (document.getElementById("diff_search_box").checked) {
Array.from(data.get(map).get("difficulties").keys()).forEach(function(diff) {
if (!(diff.toLowerCase().indexOf(string) >= 0)) {
data.get(map).get("difficulties").delete(diff)
}
})
if (Array.from(data.get(map).get("difficulties").keys()).length = 0) {
data.delete(map)
}
}
}
})
in this situation, I'm supposed to get a dictionary such as:
{
"593620 Linked Horizon - Shinzou o Sasageyo! [TV Size]": {
"difficulties": {"Titan": 86813}
}
}
Huge number of problems with this code. My recommendation is don't write so much code without running it to make sure it works first. Write small pieces at a time and run it as you go making sure everything works along the way.
Issue number one is you cannot initialize a map with an object like that. The Map must be initialized with an array of arrays that are each two elements long, each containing the key value pairs for the map. You can fix this by wrapping the object in Object.entries() as that will return the key vale pairs for the object.
Second problem is titan is a string so it should be "titan".
Number three, you're calling .get on an object in the line data.get(map).get("difficulties"). Objects do not have .get, you have to use brackets or dot syntax: data.get(map).difficulties or data.get(map).difficulties.
Fourth, I think you don't actually want to delete the data from the map. If you did, when the user changes the search text the old data would still be gone.
Why are you using map anyways? you can simply use a normal object.
Just do this if you must use maps:
var data = new Map(Object.entries({
"593620 Linked Horizon - Shinzou o Sasageyo! [TV Size]": {
"difficulties": {"Titan": 86813}
},
"859608 LiSA - ADAMAS (TV Size)": {
"difficulties": {"Kibbleru's Blue Rose": 899}
},
"940746 CHiCO with HoneyWorks - Kimi ga Sora Koso Kanashikere": {
"difficulties": {"Taeyang's Extra": 72321}
}
}));
var string = 'titan';
function search(s) {
var r = {};
for( const [key, value] of data ) {
for( const diffKey in value.difficulties ) {
if(diffKey.toLowerCase().indexOf(string) != -1)
r[key] = value;
}
}
return new Map(Object.entries(r));
}
With this function, you can do search(string) and it will return you the map that you were wanting originally.
Mainly you should writing a bunch of code without running anything.
Map needs an iterable like an array passed to it such as:
new Map([['Key 1', 'Value 1'], ['Key 1', 'Value 1']])
You can't pass an object literal to it but you can easily use Object.entries() to extract the needed array from your object.
Then you can use Map.prototype.forEach() to loop over all the Map entries
var data = {"593620 Linked Horizon - Shinzou o Sasageyo! [TV Size]": {"difficulties": {"Titan": 86813}}, "859608 LiSA - ADAMAS (TV Size)": {"difficulties": {"Kibbleru's Blue Rose": 899}},"940746 CHiCO with HoneyWorks - Kimi ga Sora Koso Kanashikere": {"difficulties": {"Taeyang's Extra": 72321}}};
const map = new Map(Object.entries(data));
map.forEach((value, key) =>{
const {difficulties} = value;
console.log('Map key:', key.toLowerCase());
// if(someCondition){
// map.delete(key)
// }
Object.entries(difficulties).forEach(([k,v])=>{
console.log('Diff key:', k, ' Diff value:', v)
// if(k.toLowerCase().includes('titan')){
// delete difficulties[key];
// }
})
console.log('*****************************')
})
surprising to see none of the previous answer saw that, another person on a discord server i do support for software stuff on pointed out the last if condition and the fact it's missing a = so it appear as
if (Array.from(data.get(map).get("difficulties").keys()).length == 0) {
// was = before, == now
data.delete(map)
}
so now i indeed obtain a data dictionary with only 1 element containing the map which also have the difficulty that's contained in the specified string.

How to convert arrays to objects in javascript?

How could I rewrite this code to object javascript. Since Array usage is prohibed, I can only use objects here. Insted of pushing values to array, I would like to push this values into objects.
var container = [];
document.addEventListener("submit", function(e){
e.preventDefault();
});
window.addEventListener("load",function(){
var submit = document.getElementsByClassName("btn-primary");
submit[0].addEventListener("click",add,false);
document.getElementById("pobrisi").addEventListener("click",deleteAll,false);
var dateElement = document.getElementById('datum');
dateElement.valueAsDate = new Date();
var today = new Date();
var dd = today.getDate();
var mm = today.getMonth()+1;
var yyyy = today.getFullYear();
if(dd<10){
dd='0'+dd
}
if(mm<10){
mm='0'+mm
}
today = yyyy+'-'+mm+'-'+dd;
dateElement.setAttribute("min",today);
});
function add() {
var title = document.getElementById("title").value;
var type = document.getElementById("type").value;
var datum = document.getElementById("datum").value.split("-");
datum = datum[2]+". "+datum[1]+". "+datum[0];
var data = new Book(title,type,datum);
container.push(data.add());
display();
}
function display(data) {
var destination = document.getElementById("list");
var html = "";
for(var i =0;i <container.length; i++) {
html +="<li>"+container[i]+"</li>";
}
destination.innerHTML = html;
}
function deleteAll(){
container=[];
document.getElementById("list").innerHTML="";
}
Wondering if is possible to write this code whitout any array usage.
initial remarks
The problem here, in my estimation, is that you haven't learned the fundamentals of data abstraction yet. If you don't know how to implement an array, you probably shouldn't be depending on one quite yet. Objects and Arrays are so widespread because they're so commonly useful. However, if you don't know what a specific data type is affording you (ie, what convenience does it provide?), then it's probable you will be misusing the type
If you take the code here but techniques like this weren't covered in your class, it will be obvious that you received help from an outside source. Assuming the teacher has a curriculum organized in a sane fashion, you should be able to solve problems based on the material you've already covered.
Based on your code, it's evident you really have tried much, but why do you think that people here will come up with an answer that your teacher will accept? How are we supposed to know what you can use?
a fun exercise nonetheless
OK, so (we think) we need an Array, but let's pretend Arrays don't exist. If we could get this code working below, we might not exactly have an Array, but we'd have something that works like an array.
Most importantly, if we could get this code working below, we'd know what it takes to make a data type that can hold a dynamic number of values. Only then can we begin to truly appreciate what Array is doing for us.
// make a list
let l = list(1) // (1)
// push an item on the end
l = push(l, 2) // (1 2)
// push another item on the end
l = push(l, 3) // (1 2 3)
// display each item of the list
listeach(l, function (x) {
console.log(x)
})
// should output
// 1
// 2
// 3
runnable demo
All we have to do is make that bit of code (above) work without using any arrays. I'll restrict myself even further and only use functions, if/else, and equality test ===. I see these things in your code, so I'm assuming it's OK for me to use them too.
But am I supposed to believe your teacher would let you write code like this? It works, of course, but I don't think it brings you any closer to your answer
var empty = function () {}
function isEmpty (x) {
return x === empty
}
function pair (x,y) {
return function (p) {
return p(x,y)
}
}
function head (p) {
return p(function (x,y) {
return x
})
}
function tail (p) {
return p(function (x,y) {
return y
})
}
function push (l, x) {
if (isEmpty(l))
return list(x)
else
return pair(head(l), push(tail(l), x))
}
function list (x) {
return pair(x, empty)
}
function listeach (l, f) {
if (isEmpty(l))
return null
else
(f(head(l)), listeach(tail(l), f))
}
// make a list
let l = list(1) // (1)
// push an item on the end
l = push(l, 2) // (1 2)
// push another item on the end
l = push(l, 3) // (1 2 3)
// display each item of the list
listeach(l, function (x) {
console.log(x)
})
closing remarks
It appears as tho you can use an Object in lieu of an Array. The accepted answer (at this time) shows a very narrow understanding of how an object could be used to solve your problem. After this contrived demonstration, are you confident that you are using Objects properly and effectively?
Do you know how to implement an object? Could you fulfill this contract (below)? What I mean by that, is could you write the functions object, set, and get such that the following expressions evaluated to their expected result?
In case it's not obvious, you're not allowed to use Object to make it happen. The whole point of the exercise is to make a new data type that you don't already have access to
m = object() // m
set(m, key, x) // m
get(m, key) // x
set(m, key2, y) // m
get(m, key2) // y
set(m, key3, set(object(), key4, z)) // m
get(get(m, key3), key4) // z
I'll leave this as an exercise for you and I strongly encourage you to do it. I think you will learn a lot in the process and develop a deep understanding and appreciation for what higher-level data types like Array or Object give to you
Since this is a homework I feel like I shouldn't solve it for you, but rather help you in the right direction.
Like Slasher mentioned you can use objects
With JavaScript object one book would look something like
const book = {
title: 'my awesome title',
type: 'novel'
};
book is the object
title is a property with a value 'my awesome title'
type is a property with a value 'novel'
But objects can also have other objects as values. Something like
const BookShelf= {
Book1: {
Title: 'my awesome title',
Type: 'novel'
},
Book2: {
Title: 'my horrible title',
Type: 'sci-fi'
}
};
You can reference the books in the bookshelf in two ways
const book1 = BookShelf.Book1 // Returns the book1 object
const title1 = Book1.Title; // Get the title
const sametitle = BookShelf.Book1.Title // Returns title for book1, same as above.
You can also use brackets:
const book1 = BookShelf['Book1'];
const title1 = BookShelf['Book1']['Title];
You can even make new properties on a object like this:
const Book3 = {
Title: 'running out of ideas'
Type: 'memoir'
};
BookShelf['Book3'] = Book3;
Now the BookShelf has a Book3 property. So your BookShelf object looks like
const BookShelf= {
Book1: {
Title: 'my awesome title',
Type: 'novel'
},
Book2: {
Title: 'my horrible title',
Type: 'sci-fi'
},
Book3 = {
Title: 'running out of ideas'
Type: 'memoir'
};
};
That should get you started :)
JavaScript Objects is a good way to go
1- define a new object:
var myVar = {};
or
var myVar = new Object();
2- usage
// insert a new value, it doesn't matter if the value is a string or int or even another object
// set a new value
myVar.myFirstValue="this is my first value";
// get existing value and do what ever you want with it
var value = myVar.myFirstValue

Push a var in an array

Im fairly new to programming. Mostly I can find the solution to my problems online but not this time. I've found serveral posts about pushing a variable into an array, however when I console.log the array to check if the variable is actually in the array, he doesn't return the name of the variable that I want. What I get back is: [Card, Card], and what I want to see is: [card_Fireball, card_Waterbolt, etc]. The code I use is:
var Deck = [];
function Card(name, type, cost, points, damage, heal){
this.name = name;
this.type = type;
this.cost = cost;
this.points = points;
this.damage = damage;
this.heal = heal;
}
var card_Fireball = new Card("Fireball", "spell", 2, 1, 3, 0);
var card_Waterbolt = new Card("Waterbolt", "spell", 2, 1, 3, 0);
Deck.push(card_Fireball);
Deck.push(card_Waterbolt);
console.log(Deck);
The solution is probably fairly simple but I can't figure it out with my beginner experience :P Thanks for the help!!
You are doing everything correct just replace console.log with following:
console.log(JSON.stringify(Deck));
Access the card names with "Deck[x].name", where x is the index of the card in the array Deck.
To get all the names:
for(i=0;i<Deck.length;i++){
console.log(Deck[i].name);
}
Assuming you name all your cards the same way as you did in your example, you could use this to get the variable names:
for(i=0;i<Deck.length;i++){
console.log('card_' + Deck[i].name);
}
If you want to get an array of the variable names you have used, those are lost on the way.
In case you want an array of the names or any other property, try making a new array and pushing every value to it.
var names = [];
Deck.map(function(v) { names.push(v.name) })
console.log(names);
Output:
["Fireball", "Waterbolt"]

JavaScript database correlation

I've been trying to 'correlate' between user picked answers and an object property name so that if the two matches then it will display what is inside.
My program is a recipe finder that gives back a recipe that consists of the ingredients the user picked.
my code currently looks like:
//property are the ingredients and the value are the recipes that contain those ingredients. The map is automatically generated
``var map = {
"pork" : [recipe1, recipe2, ...],
"beef" : [],
"chicken" :[],
}
//this gets the user pick from the dom
var cucumber = specificVegetable[7];
var lemon = specificFruits[0];
//Then this code finds the intersection of the recipe(recipes that use more than one ingredients)
function intersect(array1, array2)
{
return array1.filter(function(n) {
return array2.indexOf(n) != -1
});
}
var recipiesWithLemon = map["lemon"]; **// makes the lemon object is map**
var recipiesWithCucumber = map["cucumber"]; **// makes the cucumber object in map**
//Here is where I am stuck
function check(){
var both = intersect(recipiesWithLemon, recipiesWithCucumber);
if ( cucumber.checked && lemon.checked){
for (var stuff in map){
if(stuff="cucumber" && stuff="lemon"){
return both;
}
}
}
}
check();
so basically what I tried to do was I made my intersect and then if user pick is lemon and cucumber then look at the properties in the map object. if the name of the property equals to the exact string then return both. That was the plan but the code does not work and I'm not sure how to fix it.
My plan is to write code for every possible outcome the user may makes so I need to find the correlation between the user pick and the map which stores the recipe. I realize this is not the most effective way but I'm stumped on how to do it another way.
Thanks for the help.
Im using the open source project jinqJs to simplify the process.
I also changed your map to an array of JSON objects. If you must have the map object not as an array, let me know. I will change the sample code.
var map = [
{"pork" : ['recipe1', 'recipe2']},
{"beef" : ['recipe3', 'recipe4']},
{"peach" :['recipe5', 'recipe6']},
{"carrot" :['recipe7', 'recipe8']}
];
var selectedFruit = 'peach';
var selectedVeggie = 'carrot';
var selections = [selectedFruit, selectedVeggie];
var result = jinqJs().from(map).where(function(row){
for(var f in row) {
if (selections.indexOf(f) > -1)
return true;
}
return false;
}).select();
document.body.innerHTML += '<pre>' + JSON.stringify(result, null, 2) + '</pre><br><br>';
<script src="https://rawgit.com/fordth/jinqJs/master/jinqjs.js"></script>

Categories

Resources