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));
Related
Been scratching my head on this one for an entire evening with no solution in sight.
Put simply
I am querying two arrays from two separate APIs.
They return data in following format:
API 1
[{
balance: 4444,
age: "18",
gender: "Male",
level: "2",
name: "Joe"
}, {
balance: 3333,
age: "45",
gender: "Male",
level: "3",
name: "Angel"
}
}]
API 2
{
Joe: {
score: 32
},
Angel: {
score: 22
}
}
I need to match the object keys from the second API to the name value of playerInfo from first API so a new array is made that is completely flat like this:
[{
balance: 4444,
age: "18",
gender: "Male",
level: "2",
name: "Joe",
score: 32
}, {
balance: 3333,
age: "45",
gender: "Male",
level: "3",
name: "Angel",
score: 22
}
}]
Here's where I am being stone walled at the moment
var result = []
const matchKeys = (data, data1) => {
let arr = []
arr.push(data1)
data.map(item => {
arr.map(item1 => {
if (item.name === Object.keys(item1)) {
result.push(Object.assign(item, item1))
console.log(result)
}
})
})
}
matchKeys(api1, api2)
I suspect I'm not getting very far because I am not properly accessing my second dataset because there is no index that keeps track of which object I am supposed to pair up with corresponding value in the arrays.
Appreciate any help
You can implement that using Array.map.
const input1 = [{
balance: 4444,
age: "18",
gender: "Male",
level: "2",
name: "Joe"
}, {
balance: 3333,
age: "45",
gender: "Male",
level: "3",
name: "Angel"
}];
const input2 = {
Joe: {
score: 32
},
Angel: {
score: 22
}
}
function matchKeys(arr1, arr2) {
const result = arr1.map((item) => {
if (input2[item.name]) {
return { ...item, ...input2[item.name] };
}
return item;
});
return result;
}
console.log(matchKeys(input1, input2));
you could use the property of the second object as a way to search the right name.
const input1 = [{
balance: 4444,
age: "18",
gender: "Male",
level: "2",
name: "Joe"
}, {
balance: 3333,
age: "45",
gender: "Male",
level: "3",
name: "Angel"
}];
const input2 = {
Joe: {
score: 32
},
Angel: {
score: 22
}
}
const matchKeys = (data, data1) => {
return data.map((item) => ({ ...item, score: data1[item.name] ? data1[item.name].score : 0 }));
}
console.log(matchKeys(input1, input2));
also checked if it has a name and if for some reason it didn't I inserted a default score.
In my angular project i have a DataSource like
[
{id: "1", name: "John", age: "23", gender:"M", Role: "Student"},
{id: "2", name: "Smith", age: "24", gender:"M", Role: "Teacher"},
{id: "3", name: "Jeff", age: "23", gender:"M", Role: "Student"},
{id: "4", name: "Ronald", age: "25", gender:"M", Role: "Teacher"},
{id: "5", name: "Ronak", age: "23", gender:"M", Role: "Student"}
]
I need to check if any two or more lines of data are same or not based on multiple conditions. Eg : If any two lines have same age and gender and Role then return their Names
So the Expected Output will be
[John,Jeff, Ronak]
Since they share the same age, gender and Role
else
[]
I tried to group the array, but I didn't find any solution to group it using multiple conditions, then tried nested loops, but seems inefficient and the results were not as expected.
You could take a joined key for the wanted properties, collenct the names for the group and return all names who are in a group with three or more items.
var data = [{ id: "1", name: "John", age: "23", gender: "M", Role: "Student" }, { id: "2", name: "Smith", age: "24", gender: "M", Role: "Teacher" }, { id: "3", name: "Jeff", age: "23", gender: "M", Role: "Student" }, { id: "4", name: "Ronald", age: "25", gender: "M", Role: "Teacher" }, { id: "5", name: "Ronak", age: "23", gender: "M", Role: "Student" }],
keys = ['age', 'gender', 'Role'],
groups = data.reduce((r, o) => {
const key = keys.map(k => o[k]).join('|');
r[key] = r[key] || [];
r[key].push(o.name);
return r;
} , {}),
result = Object.values(groups).flatMap(a => a.length >= 3 ? a : []);
console.log(result);
console.log(groups);
I would use a helper function to group the data appropriately, and pass it a function that generates a unique key from the important data. Something like this:
// Utility functions
const groupBy = (fn) => (xs) =>
xs .reduce ((a, x) => ({... a, [fn(x)]: [... (a [fn (x)] || []), x]}), {})
const getProp = (obj) => (prop) =>
obj [prop]
// Helper function
const makeKey = (props) => (record) =>
props .map (getProp (record)) .join('|')
// Main function
const multipleMatch = (props) => (data) =>
Object
.values (groupBy (makeKey(props)) (data))
.filter (arr => arr.length > 1)
// Demos
const data = [{id: "1", name: "John", age: "23", gender:"M", Role: "Student"}, {id: "2", name: "Smith", age: "24", gender:"M", Role: "Teacher"}, {id: "3", name: "Jeff", age: "23", gender:"M", Role: "Student"}, {id: "4", name: "Ronald", age: "25", gender:"M", Role: "Teacher"}, {id: "5", name: "Ronak", age: "23", gender:"M", Role: "Student"}]
console .log (multipleMatch (['age', 'gender', 'Role']) (data))
// Changing the age of one to get two different shared groups
const data2 = [{id: "1", name: "John", age: "23", gender:"M", Role: "Student"}, {id: "2", name: "Smith", age: "24", gender:"M", Role: "Teacher"}, {id: "3", name: "Jeff", age: "23", gender:"M", Role: "Student"}, {id: "4", name: "Ronald", age: "24", gender:"M", Role: "Teacher"}, {id: "5", name: "Ronak", age: "23", gender:"M", Role: "Student"}]
console .log (multipleMatch (['age', 'gender', 'Role']) (data2))
The makeKey and getProp functions could easily be inlined. But breaking out groupBy seems to make the problems much clearer.
This returns an array of arrays of objects. If you want just their names, it's easy to tack on .map (group => group .map (record => record .name)), or, replacing that initial .map with .flatMap, you get a single array at the cost of losing the potential for reporting on multiple groups.
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)
There are two object array, some of them have the same key, I'd like to merge the same key in the first array. I have pasted my code.I used nested loop, but the performance was bad O(n²). Maybe I need another method to enhance performance.(I can't use ES6 for some reason, so I'll appreciate if it is the ES5 method.)
var people = [
{
id: "001",
name: "David",
age: 29
},
{
id: "002",
name: "Lucia",
age: 41
},
{
id: "003",
name: "Steve",
age: 18
}
];
var address = [
{
id: "001",
city: "Barcelona"
},
{
id: "002",
city: "Paris"
},
{
},
{
id: "003",
city: "Tokyo"
},
{
id: "004",
city: "Barcelona"
}
];
My code
people.forEach(function(item) {
var id = item.id;
address.forEach(function(location) {
if (location.id == id) {
item.address = location.address
}
});
});
Result
var people = [
{
id: "001",
name: "David",
age: 29,
city: "Barcelona"
},
{
id: "002",
name: "Lucia",
age: 41,
city: "Paris"
},
{
id: "003",
name: "Steve",
age: 18,
city: "Tokyo"
}
];
The new people array is I preferred.
You could take a Map with all addresses and then map new object with extended properties of the map.
This approach takes all properties of address objects.
var people = [{ id: "001", name: "David", age: 29 }, { id: "002", name: "Lucia", age: 41 }, { id: "003", name: "Steve", age: 18 }],
address = [{ id: "001", city: "Barcelona" }, { id: "002", city: "Paris" }, {}, { id: "003", city: "Tokyo" }, { id: "004", city: "Barcelona" }],
map = new Map(address.map(o => [o.id, o])),
result = people.map(o => Object.assign({}, o, map.get(o.id)));
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
Make a Map with cities by id, and use it when iterating over the people array to find out the city:
let cities = new Map(address.map(a => [a.id, a.city]));
let people2 = people.map(p => ( {...p, city: cities.get(p.id)} ));
You could use Array#map to iterate over people, and Array#find to find the corresponding address from id within iterations:
const people = [{id: "001",name: "David",age: 29 },{ id: "002", name: "Lucia", age: 41
},{ id: "003", name: "Steve", age: 18 }],
address = [{ id: "001", city: "Barcelona" },{ id: "002", city: "Paris" },{ },{ id: "003", city: "Tokyo" },{ id: "004", city: "Barcelona" }];
console.log(
people.map(p => ({
...p,
...address.find(a => (p.id === a.id))
}))
);
However, that's supposing that the properties' name of address's items are not the same as people's ones.
The code below is not tested but it should work
// create an object to store them
const mergedItems = {};
// merge the 2 arrays so you only map them once (just for shorter code)
people.concat(address).map(entity => {
// add each entity on the object and id as a key
mergedItems[entity.id] = {
// if the key exist, it will merge it with the new entity
...mergedItems[entity.id],
...entity,
}
)
// this is your merged items
// Object.values will convert it from object to array
const finalItems = Object.values(mergedItems);
I used map instead of for loop because it is faster: https://codeburst.io/javascript-map-vs-foreach-f38111822c0f
I have used Object.assign method to add values from address
var people = [{ id: "001", name: "David", age: 29 }, { id: "002", name: "Lucia", age: 41 }, { id: "003", name: "Steve", age: 18 }],
address = [{ id: "001", city: "Barcelona" }, { id: "002", city: "Paris" }, {}, { id: "003", city: "Tokyo" }, { id: "004", city: "Barcelona" }];
people.forEach(function(item,pos){
Object.assign(item,{},address[address.findIndex(o=>o.id == item.id)]);
});
console.log(people);
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