Related
Context: I want to be able to look through my nested arrays of objects and depending on the array key that property belonged to then prepend the string.
Issue: I was able to do it before I changed my data structure to include more objects within the parent array. Probably not the most efficient way to do it but it worked (appreciate any pointers on tidying this up).
method to append:
for (let key in temps) {
let test = temps[key].display;
if (key === "room1") {
temps[key].display = "Our friend: " + test;
}
if (key === "room2") {
temps[key].display = "Our friend: " + test;
}
if (key === "room3") {
temps[key].display = "Unknown:" + test;
}
}
So I am appending the value of display depending on the parent key they came from "room1, room2 or room3".
Original data structure:
let temps = {
room1: { id: 1, display: "shahid" },
room2: { id: 2, display: "akram" },
room3: { id: 3, display: "zia" }
};
New data structure:
let temps = {
room1: [{ id: 1, display: "shahid" }, { id: 11, display: "Zen" }],
room2: [{ id: 2, display: "akram" }, { id: 12, display: "Julia" }],
room3: [{ id: 3, display: "zia" }, { id: 13, display: "Octane" }]
};
So how do I get the method to work with my new data structure... better still, whats a better way of doing this if any please?
As your new structure has an extra (array) layer, you need an extra level of looping:
let temps = {
room1: [{ id: 1, display: "shahid" }, { id: 11, display: "Zen" }],
room2: [{ id: 2, display: "akram" }, { id: 12, display: "Julia" }],
room3: [{ id: 3, display: "zia" }, { id: 13, display: "Octane" }]
};
for (let key in temps) {
for (let item of temps[key]) {
let test = item.display;
if (key === "room1") {
item.display = "Our friend: " + test;
}
if (key === "room2") {
item.display = "Our friend: " + test;
}
if (key === "room3") {
item.display = "Unknown:" + test;
}
}
}
console.log(temps);
Remarks
There are a few things you could improve. For instance, it is a pity that you overwrite the original display name, which really is a user name. The way it gets displayed should better be a separate property. Imagine that such a user-object would move to another room, and then updating that property...
If your rooms are really called room1, room2, ...etc, then using those as object keys is not really called for. Then you are better off with an array, where the index determines the room.
I would also suggest using more descriptive variable names. temps or test are not very descriptive of what they really represent. rooms and name would probably better describe what they are.
For instance:
let rooms = [
[{ id: 1, name: "shahid" }, { id: 11, name: "Zen" }],
[{ id: 2, name: "akram" }, { id: 12, name: "Julia" }],
[{ id: 3, name: "zia" }, { id: 13, name: "Octane" }]
];
for (let [roomId, room] of rooms.entries()) {
for (let item of room) {
item.display = (roomId === 2 ? "Unknown: " : "Our friend: ") + item.name;
}
}
console.log(rooms);
Or in an object oriented way, where you can define methods to move users in and out of a room, and where the display feature can determine the string dynamically on-the-fly (as a getter):
class User {
constructor(id, name) {
this.id = id;
this.name = name;
this.room = null;
}
exitRoom() {
if (this.room) this.room.removeUser(this);
}
enterRoom(room) {
room.addUser(room);
}
get display() {
return (this.room?.hasFriends ? "Our friend: " : "Unknown: ") + this.name;
}
}
class Room {
constructor(name, hasFriends=false) {
this.name = name;
this.users = [];
this.hasFriends = hasFriends;
}
addUser(user) {
if (user.room) user.room.removeUser(user);
user.room = this;
this.users.push(user);
return this;
}
removeUser(user) {
if (user.room != this) return;
this.users.splice(this.users.indexOf(user), 1);
user.room = null;
}
}
let rooms = [
new Room("room1", true)
.addUser(new User(1, "shahid"))
.addUser(new User(11, "Zen")),
new Room("room2", true)
.addUser(new User(2, "akram"))
.addUser(new User(12, "Julia")),
new Room("room3", false)
.addUser(new User(3, "zia"))
.addUser(new User(13, "Octane")),
];
for (let room of rooms) {
console.log(`Room: ${room.name}`);
for (let user of room.users) {
console.log(` ${user.display}`);
}
}
let temps = {
room1: [{ id: 1, display: "shahid" }, { id: 11, display: "Zen" }],
room2: [{ id: 2, display: "akram" }, { id: 12, display: "Julia" }],
room3: [{ id: 3, display: "zia" }, { id: 13, display: "Octane" }]
};
temps = Object.keys(temps).map(function (key) {
return { [key]: temps[key] };
});
for (let i of temps) {
for (let key in i) {
if (key === "room1") {
i[key].forEach(e=>e.display = "Our friend: "+e.display);
}
if (key === "room2") {
i[key].forEach(e=>e.display = "Our friend: "+e.display );
}
if (key === "room3") {
i[key].forEach(e=>e.display = "Unknown: "+e.display );
}
}
}
console.log(temps)
I'm trying to improve the way I write javascript and am looking for a better way that calls a helper function and passes in a variable into that function rather than writing the actual filter function. To explain better, this works:
courses = courses.filter(course => course.id == 3);
But I'd rather just be able to put something like:
courses.filterId(3);
And put the helper function at the bottom.
So in other words, fixing the code inbetween the /* ERROR INBETWEEN HERE */ comments may be the best way of asking for help.
Why is the error logging this message? courses.filterId is not a function
Thanks for any help here.
let tutors = [
{
name: "Bob",
age: 29,
id: 1
},
{
name: "Charlie",
age: 24,
id: 2
},
{
name: "Elanor",
age: 54,
id: 3
},
{
name: "Michael",
age: 66,
id: 4
}
],
courses = [
{
code: "AA01",
description: "Javascript IIFEs, maps, filters, reduces, etc",
id: 3
},
{
code: "AO83",
description: "Arrays, for of loops, etc",
id: 1
},
{
code: "AX40",
description: "CSS, HTML",
id: 3
},
{
code: "BX92",
description: "SQL, Node",
id: 2
},
{
code: "CC24",
description: "PHP, Java",
id: 1
},
{
code: "DI30",
description: "MongoDB",
id: 4
}
],
theHTML = '<table><tr><th>Code</th><th>Description</th><th>ID</th><th>Name</th></tr>',
container = document.querySelector('#container');
courses.forEach((course) =>
tutors.forEach((tutor) =>
tutor.id == course.id &&
(course["name"] = tutor.name)
)
);
/* USE THIS IF YOU WANNA FILTER */
//courses = courses.filter(course => course.id == 3);
/* ERROR INBETWEEN HERE */
function filterId(getID){
return courses.filter(course => course.id == getID);
}
courses.filterId(3);
/* ERROR INBETWEEN HERE */
courses.forEach(function(course) {
theHTML += '<tr>';
for (let column in course) {
theHTML += '<td>' + course[column] + '</td>';
}
theHTML += '</tr>';
});
theHTML += ('</table>');
container.innerHTML = theHTML;
// without arrow functions
/*
courses.forEach(function(course) {
tutors.forEach(function(tutor) {
if (tutor.id == course.id) {
course["name"] = tutor.name;
}
});
});
*/
<div id='container'></div>
Codepen URL: https://codepen.io/anon/pen/GbMYJW
If you really want a function like that, use Lodash's _.filter:
const filtered = _.filter(courses, ["id", 3]);
let tutors = [
{
name: "Bob",
age: 29,
id: 1
},
{
name: "Charlie",
age: 24,
id: 2
},
{
name: "Elanor",
age: 54,
id: 3
},
{
name: "Michael",
age: 66,
id: 4
}
],
courses = [
{
code: "AA01",
description: "Javascript IIFEs, maps, filters, reduces, etc",
id: 3
},
{
code: "AO83",
description: "Arrays, for of loops, etc",
id: 1
},
{
code: "AX40",
description: "CSS, HTML",
id: 3
},
{
code: "BX92",
description: "SQL, Node",
id: 2
},
{
code: "CC24",
description: "PHP, Java",
id: 1
},
{
code: "DI30",
description: "MongoDB",
id: 4
}
];
const res = _.filter(courses, ["id", 3]);
console.log(res);
.as-console-wrapper { max-height: 100% important; top: auto; }
<script src="https://cdn.jsdelivr.net/npm/lodash#4.17.11/lodash.min.js"></script>
You can assign the function reference so that courses.filterId is a function.
courses.filterId = filterId
Then, use it like so:
courses.filterId(3).forEach(...)
Alternatively, you can define the function directly on the courses.filterId property:
courses.filterId = id => courses.filter(course => course.id === id)
let tutors = [
{
name: "Bob",
age: 29,
id: 1
},
{
name: "Charlie",
age: 24,
id: 2
},
{
name: "Elanor",
age: 54,
id: 3
},
{
name: "Michael",
age: 66,
id: 4
}
],
courses = [
{
code: "AA01",
description: "Javascript IIFEs, maps, filters, reduces, etc",
id: 3
},
{
code: "AO83",
description: "Arrays, for of loops, etc",
id: 1
},
{
code: "AX40",
description: "CSS, HTML",
id: 3
},
{
code: "BX92",
description: "SQL, Node",
id: 2
},
{
code: "CC24",
description: "PHP, Java",
id: 1
},
{
code: "DI30",
description: "MongoDB",
id: 4
}
],
theHTML =
"<table><tr><th>Code</th><th>Description</th><th>ID</th><th>Name</th></tr>",
container = document.querySelector("#container");
courses.forEach(course =>
tutors.forEach(
tutor => tutor.id == course.id && (course["name"] = tutor.name)
)
);
function filterId(getID) {
return courses.filter(course => course.id == getID);
}
courses.filterId = filterId;
courses.filterId(3).forEach(function(course) {
theHTML += "<tr>";
for (let column in course) {
theHTML += "<td>" + course[column] + "</td>";
}
theHTML += "</tr>";
});
theHTML += "</table>";
container.innerHTML = theHTML;
<div id='container'></div>
With courses.filterId(3) you are calling a function which is on the Array ( ie. Array.prototype) - and it's not there ! When you have defined the function filterId it is on the default window object. The simplest fix is to pass both the Array AND the ID to the filterId function, so it will look something like...
function filterId(arr,ID) { return arr.filter(course => course.id == ID) }
Hope this helps.
You try to run function filterId as member of courses array, but it doesn't exist in Array prototype.
Option 1 try to use method find link
example
let a = [{id:2, test:2}, {id:3, test:3}]
let item = a.find((item) => item.id === 2)
//result {id: 2, test: 2}
Option 2 just call filterId(getID) it take courses from function scope.
I am doing an assessment right now and I am allowed to use what ever resources I want, just a preface. The prompt I was given was to use .filter to filter out all objects with out a specific key, here is the prompt...
Write a function called cookieLoversOnly that takes
in an array and filters out every object that
does NOT have the key favoriteCookie.
cookieLoversOnly should return the filtered array.
This is what I have so far...
function cookieLoversOnly(arr){
return arr.filter(e => arr[e]===favoriteCookie)
}
Here are some examples of arr.filter(e => !e.favouriteCookie)
let people = [
{
name: 'Mr Fooman',
job: 'Dog walker',
favouriteAnimal: 'Dog'
},
{
job: 'Barman',
favouriteFood: 'Cookies',
favouriteCookie: 'Double Choc Chip',
favouriteAnimal: 'Fox'
},
{
name: 'Miss Baz',
favouriteFood: 'Caesar Salad',
favouriteCookie: 'Raisin',
favouriteAnimal: 'Elephant'
}
];
let demons = [
{
name: "demon 1",
favouriteCookie: false
},
{
name: "demon 2",
favouriteCookie: true
},
{
name: "demon 3",
favouriteCookie: undefined
},
{
name: "demon 4",
favouriteCookie: null
}
];
function cookieLoversOnly(arr){
return arr.filter(e => e.favouriteCookie)
}
console.log("people:", cookieLoversOnly(people));
console.log("demons:", cookieLoversOnly(demons));
and therefore this answer is wrong, if you take the question literally.
I have a function that needs to return the id of a country.
My list is an array of objects :
{
id: 2,
code: "AL",
name: "Albania"
}...
Here is my function to get the id needed from country
getCountryID(countryName) {
return country_list_with_id.forEach(res => {
if (res.name.toLowerCase() === countryName) {
console.log("the id is",res.id)// the log is 143
let id = res.id;
return id;
}
});
}
console.log(array.getCountryID("USA"))//undefined
so how could I get the id?
You can't. forEach is not intended to return anything, but you can use another function to get the id from the array.
Using find will return you an object which is satisfies your condition.
getCountry(countryName) {
return country_list_with_id.find(item => item.name.toLowerCase() === countryName);
}
This will return the country object and from that object you can inject the id. If nothing was found, undefined is returned. So you need to check that object first, then try to access its properties.
const country = array.getCountry("USA");
console.log(country && country.id);
You can filter your array of countries to get the country you want, and return result. countries[0] might be undefined so use an if statement from my example or ternary operator from #void's example Here's the snippet:
const countries = [{ id: 2, code: "AL", name: "Albania" }, { id: 3, code: "DZ", name: "Algeria" }, { id: 4, code: "DS", name: "American Samoa" }];
function getCountryId(code) {
const country = countries.filter(country => country.code === code);
if(country.length > 0) {
return country[0].name;
} else {
return "No such country.";
}
}
console.log(getCountryId("DZ"));
console.log(getCountryId("USA"));
You can use Array.prototype.filter in order to filter out the country by name, and then return the id of the first/last item.
const list = [{
id: 2,
code: "AL",
name: "Albania"
}, {
id: 3,
code: "DZ",
name: "Algeria"
}, {
id: 4,
code: "DS",
name: "American Samoa"
}];
function getCountryId(name) {
return (list.filter((country) => country.name === name)[0] || {}).id;
}
console.log(getCountryId('Algeria'));
console.log(getCountryId('NoneExistingCountry'));
Use need to use .filter here. This will return the items from array matching specific condition
var data = [{ id: 2, code: "AL", name: "Albania" }, { id: 3, code: "DZ", name: "Algeria" }, { id: 4, code: "DS", name: "American Samoa" }]
Array.prototype.getCountryID = function(code){
var output = this.filter(el => el.code === code);
return output.length > 0 ? output[0].id : "Not Found";
}
console.log(data.getCountryID("DS"));
console.log(data.getCountryID("something else"));
I have been trying for hours to do this using json.js but is just too much for something that seems simple. I have this example data:
var hotels = [
{ id: 101, Name: "Hotel 101", WebFacilities: [8, 9, 10] },
{ id: 102, Name: "Hotel 101", WebFacilities: [8] },
{ id: 103, Name: "Hotel 101", WebFacilities: [8, 10] }
];
var facilities = [
{ id: 8, Name: "Facility 8" },
{ id: 9, Name: "Facility 9" },
{ id: 10, Name: "Facility 10" }
];
I want to get this:
var selectedFacilities = [
{ id: 8, Name: "Facility 8", Count: 3 },
{ id: 9, Name: "Facility 9", Count: 1 },
{ id: 10, Name: "Facility 10", Count: 2 }
];
How do I do this?
So it appears you're trying to count how many of each facility there is.
Here's one way to write the query using C#:
var hotelFacilities =
from hotel in hotels
from id in hotel.WebFacilities
group id by id;
var query =
from facility in facilities
join g in hotelFacilities on facility.id equals g.Key
select new
{
id = facility.id,
Name = facility.Name,
Count = g.Count(),
};
Now if you can picture this using the method syntax, it is almost a 1:1 transformation to the linq.js version.
Note the way the compiler translates the above will usually include the GroupBy() call within the previous SelectMany() call. However written this way will make writing the linq.js equivalent query easier and less awkward.
var hotelFacilities = hotels
.SelectMany(hotel => hotel.WebFacilities)
.GroupBy(id => id);
var query = facilities
.Join(
hotelFacilities,
facility => facility.id,
g => g.Key,
(facility, g) => new
{
id = facility.id,
Name = facility.Name,
Count = g.Count(),
}
);
And the equivalent linq.js query.
var hotelFacilities = Enumerable.From(hotels)
.SelectMany("hotel => hotel.WebFacilities")
.GroupBy("id => id")
.ToArray();
var query = Enumerable.From(facilities)
.Join(
hotelFacilities,
"facility => facility.id",
"g => g.Key()",
"(facility, g) => { id: facility.id, Name: facility.Name, Count: g.Count() }"
).ToArray();
Use this:
var selectedFacilities = facilities;
for(var i = 0; i < facilities.length; i++) {
for(var j = 0; j < hotels.length; j++) {
if(hotels[j]["id"] == facilities[i]["id"]) {
// Add data
selectedFacilities[i]["Count"] = hotels[i]["WebFacilities"].length;
} else {
selectedFacilities[i]["Count"] = 0;
}
}
}