Lodash how to group array of objects by array of values? - javascript

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));

Related

JavaScript Array Filtering in Nested Arrays

I have an array that looks something like this:
const arrayObj = [
{
id: 1,
itemsList: [
{
name: "Paul",
},
{
name: "Newman",
},
],
},
{
id: 2,
itemsList: [
{
name: "Jack",
},
{
name: "Man",
},
],
},
]
What I want is to filter the objects whose itemsList contain an object with the name of a certain value. For example, I want to be able to filter out an array with objects whose inner objects with names that contain "ul" (in this case the name Paul contains "ul"), it should give me an output as such:
const outputArray = [
{
id: 1,
itemsList: [
{
name: "Paul",
},
{
name: "Newman",
},
]
}
]
So far, I've only been able to filter out a simple flat array of objects with this function:
function filterByName(array: any, string: any) {
return array.filter((obj: any) =>
["name"].some((key: any) =>
String(obj[key]).toLowerCase().includes(string.toLowerCase())
)
);
}
but I don't know how to apply it to my case.
Here you can use the some method combined with the includes method
const arrayObj = [{
id: 1,
itemsList: [{
name: "Paul",
},
{
name: "Newman",
},
],
},
{
id: 2,
itemsList: [{
name: "Jack",
},
{
name: "Man",
},
],
},
]
const getFilterArray = (name) => {
return arrayObj.filter(obj => obj.itemsList.some(x => x.name.toLowerCase().includes(name.toLowerCase())))
}
console.log(getFilterArray("ul"))
const result = arrayObj.filter(({ itemsList }) =>
itemsList.some(({ name }) => name.toLowerCase().includes('ul')));
Can you try this?

Grouping Arrays By Nested Arrays

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));

What's the simplest way to filter a list of objects based on what is on another list?

I have written too many lines to compare and then filter a list of objects based on what's in both. How can I simplify it?
const list1 = [{ name: 'John' }, { name: 'Marie' }, { name: 'Carl' }, ]
const list2 = [{ firstName: 'John' }, { firstName: 'Peter' }, { firstName: 'Carl' }, ]
Desired result: [{ name: 'John' }, { name: 'Carl' }]
Note: get objects from list1 in which the key is name.
For this use Array#filter and Array#some. Filter for every object from arr1 where for at least one element of arr2 the name is equal to the firstName.
const list1 = [{ name: 'John' }, { name: 'Marie' }, { name: 'Carl' }, ]
const list2 = [{ firstName: 'John' }, { firstName: 'Peter' }, { firstName: 'Carl' }, ]
let res = list1.filter(({name}) => list2.some(({firstName}) => name==firstName));
console.log(res);
You can use Array.filter to do this, for each item in list1, check if the item is present in list2 using Array.find.
const list1 = [{ name: 'John' }, { name: 'Marie' }, { name: 'Carl' }, ];
const list2 = [{ firstName: 'John' }, { firstName: 'Peter' }, { firstName: 'Carl' },];
let result = list1.filter(el => list2.find(el2 => el2.firstName === el.name));
console.log("Common items", result);

Flatten an object of child arrays

I have Object which look like
list:{
dynamicPerson: [
0: {
name:"Andrew",
company:"xCompany"
},
1: {
name:"Joseph",
company:"zCompany"
}
]
dynamicPerson2: [
0: {
name:"Andrew",
company:"xCompany"
},
1: {
name:"Joseph",
company:"zCompany"
}
]
}
I want it like
List:[
0: {
name:"Andrew",
company:"xCompany"
},
1: {
name:"Joseph",
company:"zCompany"
},
2: {
name:"Andrew",
company:"xCompany"
},
3: {
name:"Joseph",
company:"zCompany"
}
]
Note DynamicPerson is run time generated key.
You can iterate trought the keys of the object. Map the arrays to an array of array and then flatten it.
let flattened = Object.keys(list).map(key => list[key]).flat();
I modified your input slightly, because it was not syntactically right.
let list = {
dynamicPerson: [
{
name: "Andrew",
company: "xCompany"
},
{
name: "Joseph",
company: "zCompany"
}
],
dynamicPerson2: [
{
name: "Andrew",
company: "xCompany"
},
{
name: "Joseph",
company: "zCompany"
}
]
};
let flattened = Object.keys(list)
.map(key => list[key])
.flat();
console.log(flattened);
You'll find it yourself by looking for: convert object to array-of-key-value-pairs
But maybe look at the snipped in here: how-to-convert-an-object-to-an-array-of-key-value-pairs can help you
You can use flatMap():
Object.values(list).flatMap(s => s);
An example:
let list ={
dynamicPerson: [
{
name:"Andrew",
company:"xCompany"
},
{
name:"Joseph",
company:"zCompany"
}
]
, dynamicPerson2: [
{
name:"Andrew",
company:"xCompany"
},
{
name:"Joseph",
company:"zCompany"
}
]
}
const result = Object.values(list).flatMap(s => s);
console.log(result);
You can also use Object.values() and flat:
let list = {
dynamicPerson: [{
name: "Andrew",
company: "xCompany"
},
{
name: "Joseph",
company: "zCompany"
}
],
dynamicPerson2: [{
name: "Andrew",
company: "xCompany"
},
{
name: "Joseph",
company: "zCompany"
}
]
}
let List = Object.values(list).flat();
console.log(List);

Accessing nested array in a json

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!
})
)
)
)

Categories