How to combine Lodash _.forEach() with _.groupBy - javascript

I have an object with arrays of objects. I'm trying to loop through these arrays with _.forEach() and then group each array with _.groupBy(). But the function is just returning the original data.
const testData = {
"1": [
{ name: "john", job: "programmer" },
{ name: "jean", job: "dentist" },
{ name: "jo", job: "programmer" },
{ name: "jeff", job: "chef" },
{ name: "jock", job: "dentist" }
],
"2": [
{ name: "julie", job: "doctor" },
{ name: "billy", job: "clerk" },
{ name: "carol", job: "doctor" },
{ name: "claire", job: "clerk" },
{ name: "cedric", job: "lawyer" }
]
};
const groupedTest = data => {
return _.forEach( data, arraygroup => {
_.groupBy( arraygroup, obj => obj.job );
} );
};
const result = groupedTest(testData)
console.log( result );
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.js"></script>
I'm looking to return a new object with the arrays grouped by job, but this function is just returning the original data. I can't figure out where I've gone wrong with the logic :-( Thanks very much for any help you can give me..

_.forEach returns the original collection - use _.map and make sure you're returning everything.
const testData = {"1":[{name:"john",job:"programmer"},{name:"jean",job:"dentist"},{name:"jo",job:"programmer"},{name:"jeff",job:"chef"},{name:"jock",job:"dentist"}],"2":[{name:"julie",job:"doctor"},{name:"billy",job:"clerk"},{name:"carol",job:"doctor"},{name:"claire",job:"clerk"},{name:"cedric",job:"lawyer"}]};
const groupedTest = data => _.map(data, arraygroup => _.groupBy(arraygroup, obj => obj.job));
const result = groupedTest(testData)
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: auto; }
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.js"></script>

With lodash you could do _.values followed by _.map and then inside go with _.groupBy in order to get the grouping by job:
const data = { "1": [ { name: "john", job: "programmer" }, { name: "jean", job: "dentist" }, { name: "jo", job: "programmer" }, { name: "jeff", job: "chef" }, { name: "jock", job: "dentist" } ], "2": [ { name: "julie", job: "doctor" }, { name: "billy", job: "clerk" }, { name: "carol", job: "doctor" }, { name: "claire", job: "clerk" }, { name: "cedric", job: "lawyer" } ] };
let result = _.map(_.values(data), arr => _.groupBy(arr, 'job'))
console.log(result)
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.min.js"></script>
If you actually want to preserve the keys in the initial object then simply use _.mapValues with _.groupBy:
const data = { "1": [ { name: "john", job: "programmer" }, { name: "jean", job: "dentist" }, { name: "jo", job: "programmer" }, { name: "jeff", job: "chef" }, { name: "jock", job: "dentist" } ], "2": [ { name: "julie", job: "doctor" }, { name: "billy", job: "clerk" }, { name: "carol", job: "doctor" }, { name: "claire", job: "clerk" }, { name: "cedric", job: "lawyer" } ] };
let result = _.mapValues(data, arr => _.groupBy(arr, 'job'))
console.log(result)
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.min.js"></script>
Very similar and without the need of lodash you can do with ES6:
const data = { "1": [ { name: "john", job: "programmer" }, { name: "jean", job: "dentist" }, { name: "jo", job: "programmer" }, { name: "jeff", job: "chef" }, { name: "jock", job: "dentist" } ], "2": [ { name: "julie", job: "doctor" }, { name: "billy", job: "clerk" }, { name: "carol", job: "doctor" }, { name: "claire", job: "clerk" }, { name: "cedric", job: "lawyer" } ] };
let result = Object.values(data).map(x => x.reduce((r, {name, job}) => {
r[job] = [...(r[job] || []), {name, job}]
return r
}, {}))
console.log(result)
Difference is that we achieve the group by via Array.reduce

Another option would be to consider the use of built in functions Object.entries() and Array.reduce() to achieve what you require:
const testData = {
"1": [
{ name: "john", job: "programmer" },
{ name: "jean", job: "dentist" },
{ name: "jo", job: "programmer" },
{ name: "jeff", job: "chef" },
{ name: "jock", job: "dentist" }
],
"2": [
{ name: "julie", job: "doctor" },
{ name: "billy", job: "clerk" },
{ name: "carol", job: "doctor" },
{ name: "claire", job: "clerk" },
{ name: "cedric", job: "lawyer" }
]
};
/*
Iterate key/value pairs of testData and reduce these to a new results object
where values are nested grouping object
*/
const results = Object.entries(testData).reduce((output, [key,array]) => {
/*
Reduce array value to a group, where the grouping is based on the job key
*/
const group = array.reduce((result, item) => {
if( Array.isArray( result[ item.job ] )) {
/*
If item.job key present in result (corresponding group) then add item
to the key's group value
*/
result[ item.job ].push(item);
}
else {
/*
Otherwise, start a new group array for this yet unseen item.job key
*/
result[ item.job ] = [ item ];
}
return result;
}, {});
output[ key ] = group;
return output;
}, {});
console.log(results)
The advantage of this approach is that it is independent of the loadash library

Related

Array to Array group convert

I need to convert this array in JavaScript. I have tried many ways but not working...
value = [
{
group: "Switzerland",
id: "A",
name: "ABC"
},
{
group: "Switzerland",
id: "B",
name: "ABC3"
},
{
group: "France",
id: "C",
name: "ABC1"
},
{
group: "Italy",
id: "F",
name: "ABC3"
}
]
I need to convert the above array to the below array format.
value = [
{
name: 'Switzerland',
bank: [
{
group: "Switzerland",
id: "A",
name: "ABC"
},
{
group: "Switzerland",
id: "B",
name: "ABC3"
}
]
},
{
name: 'France',
bank: [
{
group: "France",
id: "C",
name: "ABC1"
}
]
},
{
name: 'Italy',
bank: [
{
group: "Italy",
id: "F",
name: "ABC3"
}
]
}
]
You can just iterate through the original objects and copy the values into a new object that corresponds to your new model.
let newArray = []
for (let item of value) {
let newItem = {
name: item.group,
bank: [{
group: item.group,
id: item.id,
name: item.name,
}]
}
newArray.push(newItem)
}
(You should always include some explanation about what you were trying to achieve and what is the starting point of your code, but hope this helps.)
Go through the items, and build an object with key as group.
when same group item occur, aggregate the values.
const combine = (arr) => {
const all = {};
arr.forEach((item) => {
if (!all[item.group]) {
all[item.group] = {
name: item.group,
bank: [],
};
}
all[item.group].bank.push({ ...item });
});
return Object.values(all);
};
value = [
{
group: "Switzerland",
id: "A",
name: "ABC",
},
{
group: "Switzerland",
id: "B",
name: "ABC3",
},
{
group: "France",
id: "C",
name: "ABC1",
},
{
group: "Italy",
id: "F",
name: "ABC3",
},
];
console.log(combine(value));
According to your sample
function format(data) {
const arr = [];
const temp = {};
data.forEach((obj, index) => {
const item = { name: obj.group, bank: [] };
if (temp.hasOwnProperty(obj.group)) {
arr[temp[obj.group]].bank.push(obj);
} else {
item.bank.push(obj);
arr.push(item);
}
temp[obj.group] = index;
});
return arr;
}
console.log(format(value));
https://stackblitz.com/edit/js-etadh9

How can I filter an array with an array of strings

I am running into an issue, I have a similar array of Strings in JS:
const users = [
{
age: 13,
username: "adam",
interests: []
},
{
age: 20,
username: "eve"
interests: [
{
name: "Bars",
},
{
name: "Cafe",
},
],
},
{
age: 23,
username: "alex"
interests: [
{
name: "Bars",
},
{
name: "Healthy",
},
{
name: "Japanese",
},
],
},
];
const interests = ["Bars", "Cafe"];
And I would like to filter users having the same interests as the array of interests.
I tried in different ways without getting the desired result. How should I proceed with this?
Depending on the wanted result with users with at least one matching interest or all wanted interests, you could take either Array#some or Array#every for filtering interests.
const
users = [{ age: 13, username: "adam", interests: [] }, { age: 20, username: "eve", interests: [{ name: "Bars" }, { name: "Cafe" }] }, { age: 23, username: "alex", interests: [{ name: "Bars" }, { name: "Healthy" }, { name: "Japanese" }] }],
interests = ["Bars", "Cafe"],
one = users.filter(o => interests.some(i => o.interests.some(({ name }) => name === i))),
all = users.filter(o => interests.every(i => o.interests.some(({ name }) => name === i)));
console.log(one);
console.log(all);
.as-console-wrapper { max-height: 100% !important; top: 0; }
const users = [
{
age: 13,
username: "adam",
interests: []
},
{
age: 20,
username: "eve",
interests: [
{
name: "Bars",
},
{
name: "Cafe",
},
],
},
{
age: 23,
username: "alex",
interests: [
{
name: "Bars",
},
{
name: "Healthy",
},
{
name: "Japanese",
},
],
},
];
const interests = ["Bars", "Cafe"];
function getUsers(users, interests) {
return users.map(user => {
for(let i=0; i<interests.length; i++) {
return user.interests.some(interest => interest.name == interests[i]) ? user : false
}
})
}
console.log(getUsers(users, interests))
const users = [
{
age: 13,
username: "adam",
interests: []
},
{
age: 20,
username: "eve",
interests: [
{
name: "Bars",
},
{
name: "Cafe",
},
],
},
{
age: 23,
username: "alex",
interests: [
{
name: "Bars",
},
{
name: "Healthy",
},
{
name: "Japanese",
},
],
},
];
const interests = ["Bars", "Cafe"];
const filteredData = users.filter(user => {
const userInterests = user.interests.map(interest => interest.name);
return JSON.stringify(userInterests) === JSON.stringify(interests)
} );
console.log('data ->', filteredData);
use below code
users.filter(e=>e.interests.find(q=>interests.some(w=>w==q.name)))
This snippet will return a structure of people with the same interests. The key is the interestName and the value is a array of people.
const users = [
{
age: 13,
username: "adam",
interests: [],
},
{
age: 20,
username: "eve",
interests: [
{
name: "Bars",
},
{
name: "Cafe",
},
],
},
{
age: 23,
username: "alex",
interests: [
{
name: "Bars",
},
{
name: "Healthy",
},
{
name: "Japanese",
},
],
},
];
let commonInterests = new Map();
users.forEach((user) => {
for (let interest in user.interests) {
const username = user.username;
const interestName = user.interests[interest].name;
if (commonInterests.has(interestName)) {
let knownNames = commonInterests.get(interestName);
knownNames.push(username);
commonInterests.set(interestName, knownNames);
} else {
commonInterests.set(interestName, [username]);
}
}
});
console.log(Object.fromEntries([...commonInterests]));

How to filter an array of objects with only certain properties? [duplicate]

This question already has answers here:
Extract certain properties from all objects in array
(5 answers)
Closed 2 years ago.
let arr = [
{ name: "rick", age: "44", phone: "33434", address: "florida" },
{ name: "sam", age: "33", phone: "23232", address: "milan" }
]
I only want to show only name and age, like this:
let filteredArr = [
{ name: "rick", age: "44"},
{ name: "sam", age: "33"}
]
With map
let arr = [
{ name: "rick", age: "44", phone: "33434", address: "florida" },
{ name: "sam", age: "33", phone: "23232", address: "milan" }
]
const newarr = arr.map(({name, age}) => ({name, age}))
console.log(newarr)
Based on https://stackoverflow.com/a/47916931/476951, you can do this dynamically
const arr = [
{ name: "rick", age: "44", phone: "33434", address: "florida" },
{ name: "sam", age: "33", phone: "23232", address: "milan" }
]
function filterMap (arr, fields) {
return arr.map(el =>
fields.reduce((a,c) => ({...a, [c]: el[c]}), {}))
}
const newarr = filterMap(arr, ['name', 'age'])
console.log(newarr)
In this case you map opt to use map instead of filter
let arr = [{
name: "rick",
age: "44",
phone: "33434",
address: "florida"
},
{
name: "sam",
age: "33",
phone: "23232",
address: "milan"
}
]
let filteredData = arr.map(item => {
return {
name: item.name,
age: item.age
}
});
console.log(filteredData)

How to use mapKeys and group values by key in JavaScript?

Initially, I'm having the object:
let root = {};
root["myRootNode"] = {
id1: {
age: "17",
name: "name1",
surname: "surname1"
},
id2: {
age: "11",
name: "name2",
surname: "surname2"
},
id3: {
age: "25",
name: "name1",
surname: "surname3"
}
};
And what I want to do with it, is to get it into the state:
"name1": [
{
age: "17",
surname: "surname1"
},
{
age: "25",
surname: "surname3"
}
],
"name2": [
age: "11",
surname: "surname2"
]
For me it's important to have the list/array of all objects, which contains this same property, grouped by the value of that property.
What I tried (using lodash) is:
let test = _.mapKeys(root["myRootNode"], function(value, key) {
  return value["name"];
});
But this gives me the result:
"name1": {
age: "25"
name: "name1"
surname: "surname3"
},
"name2": {
age: "11"
name: "name2"
surname: "surname2"
}
So they are not grouped and only the last value is mapped under the key which is repeating. Also in the result that I got, they are not placed under an array.
Can use groupBy and map it's values to get rid of the name property.
If you don't mind leaving the name property can simply do _.groupBy(root.myRootNode, 'name');
Personally it feels like you should be using arrays instead of objects
const res =
_(root.myRootNode)
.groupBy('name')
.mapValues((arr)=>_.map(arr, (o) =>_.omit(o,['name'])))
.value()
console.log(res)
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.10/lodash.min.js"></script>
<script>
let root = {};
root["myRootNode"] = {
id1: {
age: "17",
name: "name1",
surname: "surname1"
},
id2: {
age: "11",
name: "name2",
surname: "surname2"
},
id3: {
age: "25",
name: "name1",
surname: "surname3"
}
};
</script>
Here's a shot at it. The idea is to create an array for each new name and push all entries onto the corresponding name array.
const root = {
myRootNode: {
id1: {
age: "17",
name: "name1",
surname: "surname1"
},
id2: {
age: "11",
name: "name2",
surname: "surname2"
},
id3: {
age: "25",
name: "name1",
surname: "surname3"
}
}
};
const result = Object.values(root.myRootNode).reduce((a, e) => {
if (!(e.name in a)) {
a[e.name] = [];
}
a[e.name].push({
age: e.age,
surname: e.surname
});
return a;
}, {});
console.log(JSON.stringify(result, null, 4));

es6 filter JSON returns undefined, filter object does not

I have a filter function that is returning undefined only when JSON is passed into it. I'd like to use this function to filter objects, JSON or anything really. Whats the best way to make this work on both objects and JSON?
let a = [{
"employees": {
"employee": [{
"id": "1",
"firstName": "Tom",
"lastName": "Cruise"
}, {
"id": "2",
"firstName": "Maria",
"lastName": "Sharapova"
}, {
"id": "3",
"firstName": "James",
"lastName": "Bond"
}]
}
}];
var b = [{
name: '',
grade: 'x'
}, {
name: 'yaya',
grade: 'x'
}, {
name: 'x',
frade: 'd'
}, {
name: 'a',
grade: 'b'
}];
function findIt(arr, searchKey) {
return arr.filter(obj => Object.keys(obj).some(key => obj[key].includes(searchKey)));
}
if (a) {
console.log("I found: ", findIt(a, "James")); // breaks
}
if (b) {
console.log("I found: ", findIt(b, "yaya")); // works fine
}
You need a reference to the inner array for searching.
findIt(a[0].employees.employee, "James"));
// ^^^^^^^^^^^^^^^^^^^^^^
let a = [{ employees: { employee: [{ id: "1", firstName: "Tom", lastName: "Cruise" }, { id: "2", firstName: "Maria", lastName: "Sharapova" }, { id: "3", firstName: "James", lastName: "Bond" }] } }];
var b = [{ name: '', grade: 'x' }, { name: 'yaya', grade: 'x' }, { name: 'x', frade: 'd' }, { name: 'a', grade: 'b' }];
function findIt(arr, searchKey) {
return arr.filter(obj => Object.keys(obj).some(key => obj[key].includes(searchKey)));
}
console.log(findIt(a[0].employees.employee, "James"));
console.log(findIt(b, "yaya"));
For a deeper find, you could use an recursive approach.
function findIt(object, search) {
function find(k) {
if (object[k] === search) {
return result = object;
}
return result = findIt(object[k], search);
}
var result;
if (object && typeof object === 'object') {
Object.keys(object).some(find);
}
return result;
}
var a = [{ employees: { employee: [{ id: "1", firstName: "Tom", lastName: "Cruise" }, { id: "2", firstName: "Maria", lastName: "Sharapova" }, { id: "3", firstName: "James", lastName: "Bond" }] } }],
b = [{ name: '', grade: 'x' }, { name: 'yaya', grade: 'x' }, { name: 'x', frade: 'd' }, { name: 'a', grade: 'b' }];
console.log(findIt(a, "James"));
console.log(findIt(b, "yaya"));
console.log(findIt(a, "foo")); // undefined
.as-console-wrapper { max-height: 100% !important; top: 0; }
You can try to do a string search.
Logic
Create a copy of object but as string using JSON.stringify
Create a regex that searches for a pattern :<something>SearchValue.
Test object string with this regex and return it in filter
let a = [{ employees: { employee: [{ id: "1", firstName: "Tom", lastName: "Cruise" }, { id: "2", firstName: "Maria", lastName: "Sharapova" }, { id: "3", firstName: "James", lastName: "Bond" }] } }];
var b = [{ name: '', grade: 'x' }, { name: 'yaya', grade: 'x' }, { name: 'x', frade: 'd' }, { name: 'a', grade: 'b' }];
function findIt(arr, searchKey) {
let reg = new RegExp(':(.*?)' + searchKey, 'g');
return arr.filter(obj => reg.test(JSON.stringify(obj)));
}
console.log("I found: ", findIt(a, "James")); // breaks
console.log("I found: ", findIt(a[0].employees.employee, "James")); // breaks
console.log("I found: ", findIt(b, "yaya")); // works fine

Categories

Resources