let ages = data
.filter(isDog)
.map(dogYears)
.reduce(sum);
mL/hr
i want to find the best way of accessing array elements in a javascript object.
Eg: I want to find the first faculty name & first specializations for each course.
var students =
{
deptartment:[
{
name:'Computer Science',
age:20,
Course:[
{ id: 100000
name:'Object Oriented Programming',
faculty:[
{
id:123,
name:'John',
Specialization: [
{name: 'science'},
{name: 'Physics'}
]
}
]
},
{ id: 100001
name:'C#',
faculty:[
{
id:124,
name:'Denis',
Specialization: [
{name: 'Ecnonomics'},
{name: 'Physics'}
]
}
]
}
],
}
]
};
I know i can get the faculty name and specialization by
var courses= deptartment && deptartment.Course ;
var facultyWithSpecialization= {};
if(courses){
courses.forEach(course =>{
var fname = course.faculty && course.faculty[0].name;
var s= course.faculty && course.faculty.Specialization;
facultyWithSpecialization[fname] = s && s[0].name;
})
}
use Object.assign({}, deptartment.Course) instead of department.Course
tried to use the below code but it doesn't make much difference.
var courses=Object.values(Object.assign({}, deptartment.Course));
var fname = Object.values(Object.assign({}, course.faculty[0].Specialization[0]));
Expecting
'John': 'science'
'Denis': 'Ecnonomics'
You can try this. There were many error in the object including spelling mistakes and formatting
var students = {
deptartment: [{
name: 'Computer Science',
age: 20,
Course: [{
id: 100000,
name: 'Object Oriented Programming',
faculty: [{
id: 123,
name: 'John',
Specialization: [{
name: 'science'
},
{
name: 'Physics'
}
]
},
{
id: 124,
name: 'Denis',
Specialization: [{
name: 'Ecnonomics'
},
{
name: 'Physics'
}
]
}
]
}],
}]
}
var obj = {};
students.deptartment.forEach((e) => {
e.Course.forEach((k) => {
k.faculty.forEach((l) => {
obj[l.name] = l.Specialization[0].name
})
})
})
console.log(obj)
I think you meant department instead of deptartment.
I modified a bit your JSON as it was a bit buggy:
var students = {
departments:[
{
name:'Computer Science',
age:20,
Courses:[
{ id: 100000,
name:'Object Oriented Programming',
faculty:[
{
id:123,
name:'John',
Specialization: [
{name: 'science'},
{name: 'Physics'}
]
},
{
id:124,
name:'Denis',
Specialization: [
{name: 'Ecnonomics'},
{name: 'Physics'}
]
}
]
}
],
}]
}
You can use map to achieve this nesting:
students.departments.map(
department => department.Courses.map(
course => course.faculty.map(
student => ({
name: student.name,
specialization: student.Specialization[0].name // check nulls here!
})
)
)
)
Related
I want to group an array of objects based on a property which has an array of values,and i want to return a group for each individual value,not only for the whole array.
For example :
let crew = [
{
name:"john",
job :["electrician","carpenter"]
},
{
name: "bill",
job: ["electrician"]
},
{
name: "mark",
job: [ "carpenter"]
}
]
let groupedCrew = _.groupBy(crew,"job")
console.log(groupedCrew)
/*
carpenter:
[
{
job:
[
carpenter
],
name:
"mark"
}
],
electrician:
[
{
job:
[
"electrician"
],
name:
"bill"
}
],
electrician, carpenter:
[
{
job:
[
"electrician",
"carpenter"
],
name:
"john"
}
]
}
*/
In this example i want "john" to also appear in "electrician" group.
Any ideas ?
Once again let's group something using reduce
Here's the basic structure (plus the solution)
let crew = [{
name: "john",
job: ["electrician", "carpenter"]
},
{
name: "bill",
job: ["electrician"]
},
{
name: "mark",
job: ["carpenter"]
}
];
var obj = crew.reduce(function(agg, item) {
// grouping logic below this line
item.job.forEach(function(job) {
agg[job] = agg[job] || []
// agg[job].push (item);
// lets push only name so we can see output
agg[job].push(item.name)
})
// grouping logic above this line
return agg
}, {})
console.log(obj)
use custom .reduce() function
there is no need for lodash
const crew = [
{
name: 'john',
job: ['electrician', 'carpenter'],
},
{
name: 'bill',
job: ['electrician'],
},
{
name: 'mark',
job: ['carpenter'],
},
];
const groupedCrew = crew.reduce((groupedCrew, person) => {
person.job.forEach(job => {
if (!groupedCrew[job]) groupedCrew[job] = [];
groupedCrew[job].push(person);
});
return groupedCrew;
}, {});
console.log(JSON.stringify(groupedCrew, null, 4));
I have the following array that I'd like to transform into an Object with unique hobbies as the keys
const arr = [
{ name: 'Joe', hobbies: ['skating', 'biking', 'music'] },
{ name: 'Kim', hobbies: ['fishing', 'biking', 'karate'] },
{ name: 'Ben', hobbies: ['surfing'] },
]
I use lodash's handy groupBy function but it groups the multiple array elements into single keys like so
{
'skating,biking,music': [
{ name: 'Joe' }
],
'fishing,biking,karate': [
{ name: 'Kim' }
],
'surfing': [
{ name: 'Ben' }
],
}
What I need is the following output (note the objects are repeated for each of their respective hobbies)
{
biking: [
{ name: 'Joe' },
{ name: 'Kim' }
],
skating: [
{ name: 'Joe' }
],
karate: [
{ name: 'Kim' }
],
surfing: [
{ name: 'Ben' }
],
...
}
Is there a simple way to group this array without looping through each array element, splitting them up and regrouping? Would like to avoid this if there's better utility method out there I'm unaware of
You can iterate each item and each hobbie and then add it to a result object:
const arr = [
{ name: 'Joe', hobbies: ['skating', 'biking', 'music'] },
{ name: 'Kim', hobbies: ['fishing', 'biking', 'karate'] },
{ name: 'Ben', hobbies: ['surfing'] }
]
const result = {};
arr.forEach(item =>
item.hobbies.forEach(hobbie =>
result[hobbie] = (result[hobbie] || []).concat({name: item.name})
)
)
console.log(result);
const arr = [
{ name: 'Joe', hobbies: ['skating', 'biking', 'music'] },
{ name: 'Kim', hobbies: ['fishing', 'biking', 'karate'] },
{ name: 'Ben', hobbies: ['surfing'] }
]
const result = {};
arr.forEach(item =>
item.hobbies.forEach(hobbie =>
result[hobbie] = result[hobbie]?[...result[hobbie],{name: item.name}]: [{name: item.name}]
)
)
console.log(result);
I've renamed arr to people for better understanding.
const people = [
{ name: 'Joe', hobbies: ['skating', 'biking', 'music'] },
{ name: 'Kim', hobbies: ['fishing', 'biking', 'karate'] },
{ name: 'Ben', hobbies: ['surfing'] },
];
function transform(people) {
// get all hobbies and remove duplicates
const hobbies = [... new Set(
people.reduce((hobbies, person) => hobbies.concat(person.hobbies), [])
)];
const res = {};
// take a hobby and use it as key
for (let hobby of hobbies) {
res[hobby] = people
.filter((person) => person.hobbies.includes(hobby))
.map((person) => { return { name: person.name }; });
}
return res;
}
console.log(transform(people));
let bigArray = [
{
Name: 'Alice',
children: [
{Name: 'AliceChild1', Country: 'country1'},
{Name: 'AliceChild2', Country: 'country2'}
]
},
{
Name: 'Bob',
children: [
{Name: 'BobChild1', Country: 'country3'},
{Name: 'BobChild2', Country: 'country4'}
]
},
{
Name: 'Sam',
children: [
{Name: 'SamChild1', Country: 'country5'},
{Name: 'SamChild2', Country: 'country6'}
]
},
]
I want to remove an object from array inside another array. Property Name is unique. For an example if BobChild2 is removed bigArray should return as
let bigArray = [
{
Name: 'Alice',
children: [
{Name: 'AliceChild1', Country: 'country1'},
{Name: 'AliceChild2', Country: 'country2'}
]
},
{
Name: 'Bob',
children: [
{Name: 'BobChild1', Country: 'country3'},
]
},
{
Name: 'Sam',
children: [
{Name: 'SamChild1', Country: 'country5'},
{Name: 'SamChild2', Country: 'country6'}
]
},
]
What is the best way to do this in JavaScript ?
Updated:
My answer
function removeChild(bigArray, childName) {
let copyBigArray = []
bigArray.forEach((item) => {
let Obj = {
Name: item.Name,
children: item.children.filter(c => c.Name !== childName)
}
copyBigArray.push(Obj)
})
return copyBigArray
}
Try this way:
let bigArray = [{
Name: 'Alice',
children: [{
Name: 'AliceChild1',
Country: 'country1'
},
{
Name: 'AliceChild2',
Country: 'country2'
}
]
},
{
Name: 'Bob',
children: [{
Name: 'BobChild1',
Country: 'country3'
},
{
Name: 'BobChild2',
Country: 'country4'
}
]
}
]
bigArray.forEach(function(o) {
o.children = o.children.filter(s => s.Name != 'BobChild2');
});
console.log(bigArray);
To support any nested depth you can do something like this:
function searchAndRemove(arr, query) {
for (var i = arr.length; i > 0; i--) {
if (query == arr[i].Name) {
arr.splice(i, 1);
}
}
if (arr.children) {
searchAndRemove(arr.children, query);
}
}
searchAndRemove(bigArray, 'BobChild2');
This will go through your array recursively until it finds all occurrences of BobChild2 and removes them.
Well the structure isn't optimal because it'll require iterating over 2 arrays, but I'd use filter() (documentation) something like this:
function deepFilter(array, name) {
return array.map(arr => {
if (!arr || !arr.children) {
return arr;
}
arr.children = arr.children.filter(c => c.Name !== name);
return arr;
})
}
Filter has to return a Boolean to know if the element should be returned or not.
Map has to return an element.
If you want to remove an element from the first Array once its children are empty, you could replace the map by a filter.
function deepFilter(array, name) {
return array.filter(arr => {
if (!arr || !arr.children || !arr.children.length) {
return false;
}
arr.children = arr.children.filter(c => c.Name !== name);
return arr && arr.children && arr.children.length;
})
}
--
Use them by doing:
const new = deepFilter(bigArray, 'SamChild1')
Here is an example how you could achieve it:
let bigArray = [
{
Name: 'Alice',
children: [
{Name: 'AliceChild1', Country: 'country1'},
{Name: 'AliceChild2', Country: 'country2'}
]
},
{
Name: 'Bob',
children: [
{Name: 'BobChild1', Country: 'country3'},
{Name: 'BobChild2', Country: 'country4'}
]
},
{
Name: 'Sam',
children: [
{Name: 'SamChild1', Country: 'country5'},
{Name: 'SamChild2', Country: 'country6'}
]
},
]
function filterName(name, data) {
return data.reduce((arr, item) => {
if (item.Name != name) {
if (item.children) item.children = filterName(name, item.children)
arr.push(item)
}
return arr
}, [])
}
console.log(filterName("BobChild2", bigArray));
A main loop for the initial values of the array
Another loop for children values
The first parameter is the array itself that wants to be filtered, for example: bigArray
The second parameter is the value for the filter, for example: BobChild2
The third parameter is the key for the filter, for example: Name
let bigArray = [{
Name: 'Alice',
children: [
{ Name: 'AliceChild1', Country: 'country1' },
{ Name: 'AliceChild2', Country: 'country2' }
]
},
{
Name: 'Bob',
children: [
{ Name: 'BobChild1', Country: 'country3' },
{ Name: 'BobChild2', Country: 'country4' }
]
},
{
Name: 'Sam',
children: [
{ Name: 'SamChild1', Country: 'country5' },
{ Name: 'SamChild2', Country: 'country6' }
]
},
];
function filterBigArray(array, value, filter) {
let result = [];
bigArray.forEach(person => {
let childs = [];
person.children.forEach(children => {
if (children[filter] !== value) {
childs.push(children);
}
});
result.push(childs);
});
return result;
}
let res = filterArray(bigArray, 'BobChild2', 'Name');
console.log(res);
You can also filter different keys, for example:
let res = filterBigArray(bigArray, 'country3', 'Country');
console.log(res);
const beers = [
{
id: '100',
name: 'stoneys'
},
{
id: '200',
name: 'budweiser'
},
{
id: '300',
name: 'miller'
},
{
id: '400',
name: 'corona'
}
];
const people = [
{
name: 'steve',
teams: [
{
name: 'pirates',
beers: ['100']
},
{
name: 'penguins',
beers: ['300']
}
]
},
{
name: 'jim',
teams: [
{
name: 'indians',
beers: ['200']
},
{
name: 'blue jackets',
beers: ['100', '400']
}
]
}
];
let newPeople = people.map(fan => {
fan.teams.map(team => {
team.beers.map(beer => beers.filter(brand => brand.id === beer)[0])
});
});
Above is a sample I put together to best demonstrate my question. I am having trouble understanding why nested mapping (.map()) of object arrays is not allowing me to alter the nested data. When I console log results, I am either getting an "[undefined, undefined]' or the unchanged "people" array.
I would like to return the same array as "people" except replace the nested "beers" array (people.teams.beers[]) with corresponding objects from the "beers" array. Example of a successful result below:
{
name: 'steve',
teams: [
{
name: 'pirates',
beers: [
{
id: '100',
name: 'stoneys'
}
]
},
{
name: 'penguins',
beers: [
{
id: '300',
name: 'miller'
}
]
}
]
}
Array.map expects a function which takes single array element as parameter and returns a mapped value. In your case you're not returning any value from mapping functions therefore you're getting undefined twice
const beers = [
{
id: '100',
name: 'stoneys'
},
{
id: '200',
name: 'budweiser'
},
{
id: '300',
name: 'miller'
},
{
id: '400',
name: 'corona'
}
];
const people = [
{
name: 'steve',
teams: [
{
name: 'pirates',
beers: ['100']
},
{
name: 'penguins',
beers: ['300']
}
]
},
{
name: 'jim',
teams: [
{
name: 'indians',
beers: ['200']
},
{
name: 'blue jackets',
beers: ['100', '400']
}
]
}
];
let newPeople = people.map(fan => {
let teams = fan.teams.map(team => {
let beer = team.beers.map(beer => beers.filter(brand => brand.id === beer)[0]);
return { name: team.name, beers: beer }
});
return { name: fan.name, teams: teams }
});
console.log(newPeople);
For my React.js project I would like to create a search-filter of a nested Array. Users will search with an input-field.
var dataExample = [
{
type: "human", details: [
{id: 1, name: "Peter", description: "friendly, black-hair"},
{id: 5, name: "Susan", description: "blond"}
]
},
{
type: "animal", details: [
{id: 2, name: "Will", description: "lazy, cute"},
{id: 3, name: "Bonny", description: "beautiful"}
]
}
];
In my search-input-field I want to look for "name" or something in "description". The data structure of the array should remain the same.
The output when I'm searching for "friendly" or "Peter" should be:
[
{
type: "human", details: [
{id: 1, name: "Peter", description: "friendly, black-hair"}
]
}
];
Now I tried something like this:
let myfilter = dataExample.filter((data) => {
data.details.filter((items) => {
return (items.type.indexOf("human") !== -1 || //input of user
items.description.indexOf("friendly"))
})
})
Unfortunately, this is not how it works. Can anybody help me? Lodash would be no problem, too. Thank you so much.
You can use array#reduce with array#filter and to check for your word you can use string#incldues.
const dataExample = [ { type: "human", details: [ {id: 1, name: "Peter", description: "friendly, black-hair"}, {id: 5, name: "Susan", description: "blond"} ] }, { type: "animal",details: [ {id: 2, name: "Will", description: "lazy, cute"}, {id: 3, name: "Bonny", description: "beautiful"} ] } ],
term = 'Peter',
result = dataExample.reduce((r, {type,details}) => {
let o = details.filter(({name,description}) => name.includes(term) || description.includes(term));
if(o && o.length)
r.push({type, details : [...o]});
return r;
},[]);
console.log(result);
Here are some examples without lodash.
var dataAll = [
{
type: "human",
details: [
{id: 1, name: "Peter", description: "friendly, black-hair"},
{id: 5, name: "Susan", description: "blond"}
]
},
{
type: "animal",
details: [
{id: 2, name: "Will", description: "lazy, cute"},
{id: 3, name: "Bonny", description: "beautiful"}
]
}
];
var entryTypeFilter = data => data.type.indexOf("hum") !== -1;
var entryDetailDescFilter = data => data.description.indexOf("friend") !== -1;
var entryDetailsMapper = data => {
return {
type: data.type,
details: data.details.filter(entryDetailDescFilter)
};
};
var entryNoDetailsFilter = data => data.details && data.details.length !== 0;
var dataFilteredByType = dataAll.filter(entryTypeFilter);
var dataFilteredByDesc = dataAll.map(entryDetailsMapper);
var dataFilteredByTypeAndDesc = dataAll.filter(entryTypeFilter).map(entryDetailsMapper);
var dataFilteredByDescTrimmingEmptyDetailEntries = dataAll.map(entryDetailsMapper).filter(entryNoDetailsFilter);
In modern javascript you might want to search on how to use the ... keyword for the mapping callback functions.