Create nested array of objects from array of objects Javascript - javascript

I have the following array of objects. How can I reshape the data to get the Expected Output?
let performanceReview = [
{ "name": "Sean", "Manager": "Joe", "Performance": 5},
{ "name": "John", "Manager": "Joe", "Performance": 9},
{ "name": "Paul", "Manager": "Joe", "Performance": 0},
{ "name": "Derek", "Manager": "Greg", "Performance": 10},
{ "name": "Lisa", "Manager": "Greg", "Performance": 10},
{ "name": "Julia", "Manager": "Donna", "Performance": 7}];
Expected Output
var Series = [
{Manager: "Joe", data: [["Sean", 5], ["John", 9], ["Paul", 0]]},
{Manager: "Greg", data: [["Derek", 10],["Lisa", 10]]},
{Manager: "Donna", data: [["Julia", 7]]}];
Could someone also please help walk me through their problem solving approach.

This solution breaks the task into two steps. (The code could be shorter, but this may be a bit easier to understand than trying to squeeze all the logic into a one-liner.)
Using Array.prototype.reduce, we can make an object where each property has:
a manager's name as a key and
the two-dimensional array of minions-with-ratings as the value
Then, using the for...in syntax, we can convert each property to an independent object and push it to the output array.
See the in-code comments for clarifications.
// Main
const
originalArray = getOriginalArray(),
obj = groupByManager(originalArray),
output = formatFinalArray(obj);
console.log(output);
// We make an object because, unlike Arrays, they use named properties
function groupByManager(input){
const obj = input.reduce(
// 1st argument to `reduce` is a 'reducer' function (taking two args)
// that will be applied to each item of the array
(grouped, item) => {
// 1st arg to reducer func is the accumulated value, returned after each loop
// 2nd arg to reducer func is the item of the array for the current loop
// If there's no prop named for this manager, makes one w/ empty array as value
grouped[item.Manager] = grouped[item.Manager] || [];
// Makes a two-item array of name and performance and pushes it to prop array
grouped[item.Manager].push([item.name, item.Performance]);
// The accumulated object has been updated, is ready to be used in next loop
return grouped;
},
// 2nd arg to `reduce` (an empty obj) to be used as `grouped` during first loop
{}
);
return obj;
}
// We'll pass the object into this function to get our desired format
function formatFinalArray(obj){
const output = [];
for(let key in obj){
output.push({ Manager: key, data: obj[key] });
}
return output;
}
// Just provides our original array
function getOriginalArray(){
return [
{ "name": "Sean", "Manager": "Joe", "Performance": 5 },
{ "name": "John", "Manager": "Joe", "Performance": 9 },
{ "name": "Paul", "Manager": "Joe", "Performance": 0 },
{ "name": "Derek", "Manager": "Greg", "Performance": 10 },
{ "name": "Lisa", "Manager": "Greg", "Performance": 10 },
{ "name": "Julia", "Manager": "Donna", "Performance": 7 }
];
}

Related

How to build a new Array of Objects from existing Array of Objects, filtered to match a list of keys

I have an array of objects, example:
[
{
"fName": "Jon",
"lName": "Doe",
"age": "30",
"shirtSize": "M"
},
{
"fName": "Jane",
"lName": "Foe",
"age": "25",
"shirtSize": "M"
},
...
]
I also have a list of keys, example:
["age", "shirtSize"]
I want to take the array of objects, and build a new array of objects that match the key list array, effectively filtering the array of objects to only have the key/value pairs I want. The above are examples, and the real datasets are of course more verbose. I've brute forced it in my algorithm below and as expected, it's not very performant at all, as a result of my loop within the map. My result is like:
[
{
"age": "30",
"shirtSize": "M"
},
{
"age": "25",
"shirtSize": "M"
},
...
]
I am not using anything like lodash. How can I improve this performance?
const data = [
{
"fName": "Jon",
"lName": "Doe",
"age": "30",
"shirtSize": "M"
},
{
"fName": "Jane",
"lName": "Foe",
"age": "25",
"shirtSize": "M"
}
];
const keyList = ["age", "shirtSize"];
const filteredDataset = data.map((elem) => {
let tempHolder = {};
for (let key of keyList) {
tempHolder[key] = elem[key];
}
return tempHolder;
});
return filteredDataset;
var results = [];
for(var person of data){
var obj = {};
for(var key of keyList){
obj[key] = person[key];
}
results.push(obj);
}
The first loop iterates through data, and the inner loop iterates through keyList and adds those attributes to the temporary object, which is then pushed to the results array.
EDIT: Your code is basically the same, with yours just using map to iterate through instead of a for...of loop.
You can express the same algorithm more declaratively:
const select = (props) => (objs) =>
objs .map (o => Object .fromEntries (props .map (p => [p, o[p]])))
const items = [{fName: "Jon", lName: "Doe", age: "30", shirtSize: "M"}, {fName: "Jane", lName: "Foe", age: "25", shirtSize: "M"}]
console .log (select (["age", "shirtSize"]) (items))

How to compare elements in array objects using javascript

I am new to javascript usage.
I have a requirement to compare the field from two different array objects which are having list as below.
Array - A
[
{
"id": "xyz",
"number": "123",
"place": "Here",
"phone": "9090909090"
},
{
"id": "abc",
"number": "456",
"place": "There",
"phone": "9191919191"
},
]
Array - B
[
{
"element1" : "ert",
"id1":"iii",
"element2":"erws",
"element3":"234"
}
,
{
"element1" : "uio",
"id1":"xyz",
"element2":"puy",
"element3":"090"
}
]
The scenario is to compare for each 'id' in the list of array A, with the list of Array B to field 'id1'
Example -
I need to check from Array A -> 'id:xyz' matches the array B object field 'id1'.
Array A - id: xyz should match with id1: xyz in Array B
If the match occurs I need to pull out complete object from the array list A.
here id:xyz matches with id1:xyz
then pull out as below
[
{
"id": "xyz",
"number": "123",
"place": "Here",
"phone": "9090909090"
}
]
Please help me with the suggestions to make this work using javascript.
const A = [
{
"id": "xyz",
"number": "123",
"place": "Here",
"phone": "9090909090"
},
{
"id": "abc",
"number": "456",
"place": "There",
"phone": "9191919191"
},
];
const B = [
{
"element1" : "ert",
"id1":"iii",
"element2":"erws",
"element3":"234"
},
{
"element1" : "uio",
"id1":"xyz",
"element2":"puy",
"element3":"090"
}
];
const C = A.filter(a => B.some(b => b.id1 === a.id));
console.log(C);
// the usage of `const` here means that arrA cannot be re-declared
// this is good for data that should not be changed
const arrA = [{
"id": "xyz",
"number": "123",
"place": "Here",
"phone": "9090909090"
},
{
"id": "abc",
"number": "456",
"place": "There",
"phone": "9191919191"
},
];
const arrB = [{
"element1": "ert",
"id1": "iii",
"element2": "erws",
"element3": "234"
},
{
"element1": "uio",
"id1": "xyz",
"element2": "puy",
"element3": "090"
}
];
// slow method for long lists, fine for short lists or if there are duplicates
// compares each entry in array A to each entry in array B
const out1 = arrA.filter(x => arrB.some(y => x.id === y.id1));
console.log("Example 1: \n", out1);
// faster for long lists
// creates a set of unique values for array B's id1 parameter, ignores duplicates
// then checks that set for each entry in array A
const setB = arrB.reduce((a, b) => {
a.add(b.id1);
return a;
}, new Set());
const out2 = arrA.filter(x => setB.has(x.id));
console.log("Example 2: \n", out2)
.as-console-wrapper { min-height: 100% } /* this is just to make the stack overflow output prettier */

How to store key values of a JSON array of object in an array

I've got a JSON array of objects like :
x= {"user":[{ "name": "Jhon", "age": "18" }, { "name": "Ted", "age": "20" }]};
I would like to store every values of names of each object in a simple array but I don't know how to do that
I know that I can get values of names with JSON.parse(x)["user][0]["name"]
So I need how to get the number of objects in my array of objects : Objects.keys(JSON.parse(x)["users"]).length)
Array#map()
const data = {"user":[{ "name": "Jhon", "age": "18" }, { "name": "Ted", "age": "20" }]};
console.log(data.user.map(u=>u.name));
You can iterate over an array using the map function which takes a callback, and return exactly which property you want from each user object inside the callback. You'll be left with an array of names.
const myObject = {"user":[{ "name": "Jhon", "age": "18" }, { "name": "Ted", "age": "20" }]};
const names = myObject["user"].map((user) => {
return user["name"];
}
So you want to map the array of users (x.user) to new collection, getting only the names of the user. Take a look at https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map .
In short:
var x = {"user":[{ "name": "Jhon", "age": "18" }, { "name": "Ted", "age": "20" }]};
var y = x.user.map(user => user.name) // <-- y becomes Array [ "Jhon", "Ted" ]

How can I get the result with underscore.js filter?

Here is the test array:
var test = [
{
"id": 1,
"team": [
{
"name": "Alex",
"age": 27,
"checked": true
},
{
"name": "Bob",
"age": 35,
"checked": false
}
],
"checked": true
},
{
"id": "2",
"team": [
{
"name": "Jack",
"age": 37,
"checked": false
},
{
"name": "Tom",
"age": 29,
"checked": true
}
],
"checked": true
}];
And the result that I want to get is an array like this:
result = ["Alex", "Tom"];
The result array contains all items that the "checked" attribute equals to true in team.
I try to get the result with the underscore.js filter, but I cannot get the correct result.
If you have a better solution, please tell me.
Here is my code:
_.filter(test, function(team) {
_.filter(team, function(worker){
if(worker.checked)
return worker.name;
});});
Here's how you can do it in both underscore and lodash:
Underscore jsfiddle:
var result = _.chain(test).pluck('team').flatten().filter({checked:true}).value();
Lodash jsfiddle:
var result = _(test).pluck('team').flatten().filter({checked:true}).value();
Take the team arrays together, flatten them so you have the nested arrays, filter on the property and the result are the objects containing the name and checked being true. If you want just the names, do another pluck.
Here's an underscorejs version with a shorter filter and just giving back the names:
var result = _.chain(test).pluck('team').flatten().filter('checked').pluck('name').value();
// ["Alex", "Tom"]
You can simply use forEach function to handle this
var test = [...];
var result = [];
test.forEach(function(item) {
item.team.forEach(function(worker) {
if(worker.checked) {
result.push(worker.name);
}
})
})
console.log(result)
//Return ["Alex","Tom"]
One way to use filtering for multidimentional array is by using filter and any.
_.filter(test, function(team) {
return _.any(team.team, function(player) {
return player.checked;
});
});

How to merge two javascript arrays based on property values?

I have two arrays
array1 = [{"id":1,"name":"Michale Sharma","gender":"Male","age":25,"salary":10000},{"id":2,"name":"Sunil Das","gender":"Male","age":24,"salary":5000},{"id":3,"name":"Robin Pandey","gender":"Male","age":35,"salary":45000},{"id":4,"name":"Mona Singh","gender":"Female","age":27,"salary":12000}]
array2 = [{"Deptid":1,"Deptname":"IT"},{"Deptid":12,"Deptname":"HR"},{"Deptid":3,"Deptname":"HW"}]
Output:
{ "0": { "id": 1, "name": "Michale Sharma", "gender": "Male", "age": 25, "salary": 10000, "Deptid": 1, "Deptname": "IT" }, "1": { "id": 2, "name": "Sunil Das", "gender": "Male", "age": 24, "salary": 5000}, "2": { "id": 3, "name": "Robin Pandey", "gender": "Male", "age": 35, "salary": 45000, "Deptid": 3, "Deptname": "HW" }, "3": { "id": 4, "name": "Mona Singh", "gender": "Female", "age": 27, "salary": 12000 }, "4" :{ "Deptid": 12, "Deptname": "HR" } }
I want to merge them based on the property values e.g id of array1 and Deptid of array2
Which means if id value = 1 and Deptid value = 1, then merge the records, if not then keep the values from one array and the other will be null. In another words, kind of the functionality of FULL OUTER JOIN. Because the array data cannot be a sequential one and may not be of the same length.
I have tried with Jquery.extend as under
$.extend(true, array1,array2)
It does not accept any property but merges the arrays.
I have also seen this but it does not help.
Looks like you need to have a custom logic. Here is sample using lodash library:
var array1 = [{"id":1,"name":"Michale Sharma","gender":"Male","age":25,"salary":10000},{"id":2,"name":"Sunil Das","gender":"Male","age":24,"salary":5000},{"id":3,"name":"Robin Pandey","gender":"Male","age":35,"salary":45000},{"id":4,"name":"Mona Singh","gender":"Female","age":27,"salary":12000}]
var array2 = [{"Deptid":1,"Deptname":"IT"},{"Deptid":12,"Deptname":"HR"},{"Deptid":3,"Deptname":"HW"}]
var defaults = {
Deptid: null,
DeptName: null
};
_.each(array1, function (obj) {
var dept = _.find(array2, { Deptid: obj.id });
_.defaults(obj, dept, defaults);
});
Using LoDash, roughly something like this:
_.reduce(array1, function(res, item1) {
var found = _.find(array2, function(item2) {
return item1.id === item2.Deptid;
});
if (found) res.push(_.merge({}, item1, found));
return res;
}, []);
EDIT: Sorry, I forgot about merging empty props.
It would be something like this (unoptimized):
function join(array1, array2) {
var keys = _.keys(array2[0]);
var vals = _.map(keys, function() { return '' });
return _.map(array1, function(item1) {
var found = _.find(array2, function(item2) {
return item1.id === item2.Deptid;
});
if (found)
return _.merge({}, item1, found);
return _.merge({}, item1, _.zipObject(keys, vals));
}, []);
}

Categories