Javascript function- transform from one data structure to another - javascript

I'm trying to build a JS function to convert the data structure in the form of
'start' to the form of 'expected'.
Using JS map() method, how would I do this for the following associative array-
const start = {
Clients: {
171: { id: 171, name: 'John Smith', active: false },
172: { id: 172, name: 'Jacob Jacobson', active: true },
1441: { id: 1441, name: 'Eric Ericsson', active: true },
},
Caregivers: {
1: { id: 1, name: 'John Johnson', active: true },
37: { id: 37, name: 'James Jameson', active: false },
15: { id: 15, name: 'Aaron Aaronson', active: true },
},
Doctors: {
1147: { id: 1147, name: 'Doc Docson', active: true },
},
Hospitals: {
115: { id: 115, active: false, name: "St. Mary's" },
},
Applicants: {
17345: { id: 17345, name: 'Bob Bobson', active: true },
17346: { id: 17346, name: 'Jeff Jeffson', active: false },
17347: { id: 17347, name: 'Frank Frankson', active: true },
17348: { id: 17348, name: 'Bill Billson', active: true },
},
};
needs to be converted to-
const expected = [
{ label: 'Bill Billson', value: 17348, group: 'Applicants' },
{ label: 'Bob Bobson', value: 17345, group: 'Applicants' },
{ label: 'Frank Frankson', value: 17347, group: 'Applicants' },
{ label: 'Aaron Aaronson', value: 15, group: 'Caregivers' },
{ label: 'John Johnson', value: 1, group: 'Caregivers' },
{ label: 'Eric Ericsson', value: 1441, group: 'Clients' },
{ label: 'Jacob Jacobson', value: 172, group: 'Clients' },
{ label: 'Doc Docson', value: 1147, group: 'Doctors' },
];

.map() can't be used directly on Objects; instead you'll need to use Object.keys
const start = {
Clients: {
171: { id: 171, name: 'John Smith', active: false },
172: { id: 172, name: 'Jacob Jacobson', active: true },
1441: { id: 1441, name: 'Eric Ericsson', active: true }
},
Caregivers: {
1: { id: 1, name: 'John Johnson', active: true },
37: { id: 37, name: 'James Jameson', active: false },
15: { id: 15, name: 'Aaron Aaronson', active: true }
},
Doctors: {
1147: { id: 1147, name: 'Doc Docson', active: true }
},
Hospitals: {
115: { id: 115, active: false, name: "St. Mary's" }
},
Applicants: {
17345: { id: 17345, name: 'Bob Bobson', active: true },
17346: { id: 17346, name: 'Jeff Jeffson', active: false },
17347: { id: 17347, name: 'Frank Frankson', active: true },
17348: { id: 17348, name: 'Bill Billson', active: true }
}
};
// Get an array of properties in 'start'
// then use Array.reduce() to loop over each item
const expected = Object.keys(start).reduce( (res, gKey) => {
// gKey = 'group' name
// gVal = 'group' value
let gVal = start[gKey];
// loop over each item in the 'group'
Object.keys(gVal).forEach(iKey => {
// iKey = 'group.item' name
// iVal = 'group.item' value
let iVal = gVal[iKey];
// if the value's .active property is truthy
if (iVal.active) {
// format the result as desired and add it to the result array
res.push({
label: iVal.name,
value: iKey,
group: gKey
});
}
});
// return the result array
return res;
// start the .reduce() with an empty array
}, []);
console.log(expected);

To loop over an object, you can either use a for ... in loop, or use Object.keys to get an array of keys. For ... in will include inherited properties, so you may need to manually filter them out. Object.keys only returns own properties, so there's no need to do the filtering (but it also isn't appropriate if you need inherited properties)
Example with for ... in:
for (var prop in start) {
if (start.hasOwnProperty(prop)) {
// logs out 'Clients', then 'Caregivers', then 'Doctors', then 'Hospitals', then 'Applicants'
console.log(prop);
}
}
Example with Object.keys:
//produces array ['Clients', 'Caregivers', 'Doctors', 'Hospitals', 'Applicants']
var keys = Object.keys(start);
So if you wanted to use .map, you can start with this, and fill it in to do whatever you desire:
Object.keys(start)
.map(key => {
//do something with start[key]
//perhaps you could get Object.keys(start[key]) and loop over that as well.
});

My solution without 'forEach':
function transform(data) {
Object.entries(data).map(item => Object.values(item[1])
.map(i => i.group = item[0]))
.reduce(( acc, cur ) => acc.concat(cur), [])
.filter(item => item.active === true)
.sort((a, b) => a.group - b.group)
.map(item => {
let expected = {};
expected.label = item.name;
expected.value = item.id;
expected.group = item.group;
});
return expected;
}

Related

Flatten objects in array

Hey folks I am getting an array of objects from a response. I need to flatten all of the students objects to simply studentName but not certain how. Any help would be greatly appreciated.
Example Array:
[
{
students: {id: '123456', name: 'Student Name'},
active: true
},
{
students: {id: '123456', name: 'Student Name'},
active: true
}
]
What I am trying to do:
[
{
studentName: 'Student Name',
active: true
},
{
studentName: 'Student Name',
active: true
}
]
[
{ students: {id: '123456', name: 'Student Name'}, active: true },
{ students: {id: '123456', name: 'Student Name'}, active: true }
].map(e => ({studentName: e.students.name, active: e.active}))
You can create and return a new array of result using map as:
const arr = [
{
students: { id: "123456", name: "Student Name" },
active: true,
},
{
students: { id: "123456", name: "Student Name" },
active: true,
},
];
const result = arr.map(({ students, ...rest }) => ({
...rest,
studentName: students.name,
}));
console.log(result);
You can loop through the array and set each item's students property to the name property of the students property:
const arr = [
{students: {id: '123456', name: 'Student Name'},active: true},
{students: {id: '123456', name: 'Student Name'},active: true}
]
arr.forEach(e => e.students = e.students.name)
console.log(arr)
map over the data and return a new object on each iteration.
const data=[{students:{id:"123456",name:"Student Name"},active:!0},{students:{id:"123456",name:"Student Name"},active:!0}];
const out = data.map(obj => {
// Destructure the name and active properties
// from the object
const { students: { name }, active } = obj;
// Return the new object
return { studentName: name, active };
});
console.log(out);
You can use the .map() method to rebuild the objects in the array with whatever structure you need.
const arr = [
{
students: {id: '123456', name: 'Student Name'},
active: true
},
{
students: {id: '123456', name: 'Student Name'},
active: true
}
];
function flatten(array) {
return arr.map(({ students, active }) => {
return {
studentName: students.name,
active,
};
});
}
console.log(flatten(arr));
try this
let student =[
{
students: {id: '123456', name: 'Student Name'},
active: true
},
{
students: {id: '123456', name: 'Student Name'},
active: true
}
];
console.log(student.map(x=> ({ studentName: x.students.name,active: x.active })));

Filter array of objects by another object's values

I would like to filter an array of objects based on the values in another object. I am trying to map() the array and filter() inside the function so that I am able to get a new array with only the desired (active) fields.
I am trying to get the filter on the Object.entries(), I try to compare the keys and check if the values of the active filters are true, but I am not getting it right.
const records = [
{
id: 1,
name: "first",
date: "05/02"
},
{
id: 2,
name: "second",
date: "06/02"
},
{
id: 3,
name: "third",
date: "07/02"
},
{
id: 4,
name: "fourth",
date: "08/02"
}
];
const active = {
id: true,
name: false,
date: true
};
const result = records.map((record) => {
return Object.entries(record).filter((entry) => {
Object.entries(active).forEach((activeEntry) => {
return activeEntry[1] && activeEntry[0] === entry[0];
});
});
});
console.log(result);
This is the desired outcome
const desiredOutcome = [
{
id: 1,
date: "05/02"
},
{
id: 2,
date: "06/02"
},
{
id: 3,
date: "07/02"
},
{
id: 4,
date: "08/02"
}
];
You can filter over the entries of the object and convert it back to an object with Object.fromEntries.
const records=[{id:1,name:"first",date:"05/02"},{id:2,name:"second",date:"06/02"},{id:3,name:"third",date:"07/02"},{id:4,name:"fourth",date:"08/02"}];
const active = {
id: true,
name: false,
date: true
};
const res = records.map(x =>
Object.fromEntries(
Object.entries(x).filter(([k])=>active[k])));
console.log(res);
Simply filter the keys by the key existing and then use Object.fromEntries to go back to an object
const records = [
{
id: 1,
name: "first",
date: "05/02"
},
{
id: 2,
name: "second",
date: "06/02"
},
{
id: 3,
name: "third",
date: "07/02"
},
{
id: 4,
name: "fourth",
date: "08/02"
}
];
const active = {
id: true,
name: false,
date: true
};
const result = records.map((record) => {
return Object.fromEntries( Object.entries(record).filter(([key,value]) => active[key]));
});
console.log(result);

filter through multiple arrays and add objects from them to a single array

Example of an object in the accounts array:
const accounts = [
{
id: "5f446f2ecfaf0310387c9603",
picture: "https://api.adorable.io/avatars/75/esther.tucker#zillacon.me",
age: 25,
name: {
first: "Esther",
last: "Tucker",
},
company: "ZILLACON",
email: "esther.tucker#zillacon.me",
registered: "Thursday, May 28, 2015 2:51 PM",
},
Example of an object in the books array:
const books = [
{
id: "5f447132d487bd81da01e25e",
title: "sit eiusmod occaecat eu magna",
genre: "Science",
authorId: 8,
borrows: [
{
id: "5f446f2e2cfa3e1d234679b9",
returned: false,
},
{
id: "5f446f2ed3609b719568a415",
returned: true,
},
{
id: "5f446f2e1c71888e2233621e",
returned: true,
},
{
id: "5f446f2e6059326d9feb9a68",
returned: true,
},
{
id: "5f446f2ede05a0b1e3394d8b",
returned: true,
},
{
id: "5f446f2e4081699cdc6a2735",
returned: true,
},
{
id: "5f446f2e3900dfec59489477",
returned: true,
},
{
id: "5f446f2e6059326d9feb9a68",
returned: true,
},
{
id: "5f446f2e409f8883af2955dd",
returned: true,
},
{
id: "5f446f2e3900dfec59489477",
returned: true,
},
{
id: "5f446f2eae901a82e0259947",
returned: true,
},
{
id: "5f446f2ef2ab5f5a9f60c4f2",
returned: true,
},
{
id: "5f446f2ea6b68cf6f85f6e28",
returned: true,
},
{
id: "5f446f2eed18105706d6ca19",
returned: true,
},
{
id: "5f446f2eae901a82e0259947",
returned: true,
},
{
id: "5f446f2e91c2af00cb74e82b",
returned: true,
},
{
id: "5f446f2e5aa2bb5545a0f8a6",
returned: true,
},
{
id: "5f446f2ea508b6a99c3e42c6",
returned: true,
},
{
id: "5f446f2e50cc2da9cd80efdb",
returned: true,
},
{
id: "5f446f2e0b3e2ff72fc503e7",
returned: true,
},
{
id: "5f446f2e91c2af00cb74e82b",
returned: true,
},
{
id: "5f446f2ef795e593cd3cd19d",
returned: true,
},
{
id: "5f446f2e2f35653fa80bf490",
returned: true,
},
{
id: "5f446f2e7b9cd304fed3a8bc",
returned: true,
},
{
id: "5f446f2ed9aac23c0340aab2",
returned: true,
},
],
},
Example of objects in the authors array:
const authors = [
{
id: 0,
name: {
first: "Lucia",
last: "Moreno",
},
},
{
id: 1,
name: {
first: "Trisha",
last: "Mathis",
},
},
{
id: 2,
name: {
first: "Arnold",
last: "Marks",
},
},
I need to write the function function getBooksPossessedByAccount(account, books, authors) {} that does the following: It returns an array of books and authors that represents all books currently checked out by the given account. Look carefully at the object below, as it's not just the book object; the author object is embedded inside of it.
Output example:
getBooksPossessedByAccount(account, books, authors);
[
{
id: "5f447132320b4bc16f950076",
title: "est voluptate nisi",
genre: "Classics",
authorId: 12,
author: {
id: 12,
name: {
first: "Chrystal",
last: "Lester",
},
},
borrows: [
{
id: "5f446f2e6059326d9feb9a68",
returned: false,
},
...
],
},
]
Here's what I have so far:
function getBooksPossessedByAccount(account, books, authors) {
const accId = account.id;
const result = [];
for (let idxBks = 0; idxBks < books.length; idxBks++) {
if (
books[idxBks].borrows.id === accId &&
books[idxBks].borrows.returned === false
) {
result.push(books[idxBks]);
}
for (let idxAuth = 0; idxAuth < authors.length; idxAuth++) {
let authorIdx = authors[idxAuth];
if (authorIdx.id === result.authorId) {
return [result, { author: authorIdx }];
}
}
}
return result;
}
You need to search all the borrows, not just borrows[0]. You can use the some() method to check all of them.
Since the author information needs to be added as a property to the book object, you shouldn't be pushing it onto the booksOut array.
function getBooksPossessedByAccount(account, books, authors) {
const accId = account.id;
const booksOut = books.filter(
(book) => book.borrows.some(borrow => !borrow.returned && borrow.id === accId)
);
booksOut.forEach(book => book.author = authors.find(author => book.authorID == author.id))
return booksOut;
}
Using some should do the trick..
function getBooksPossessedByAccount(account, books, authors) {
let borrowedBooks=books.filter(book=>
book.some(borrow=>borrow.id===account.id)
)
return borrowedBooks //array of book objects
//return borrowedBooks.map(book=>book.id) //to show array of book ids
}

Push objects to new array with checked: true, if in mapped array

Can I please get some help with this scenario?
An array of strings
A function that maps the array of strings and applies to each one of them a name, key and adds one more object "checked: false".
A function that takes the mapped array and transforms it according to the argument passed, storing the value in to another array and changing the "checked" to value "true"
Ex:
const defaultProducts = [
"Laptop",
"Tablet",
"Phone",
"Ram",
"SSD",
"RasberyPi",
"Desktop",
"TV",
"Monitor"
];
const getDefaultProducts = () => {
return defaultProducts.map(products => {
return {
name: products,
checked: false
};
});
};
console.log(getDefaultProducts())
let forSale = []
function useProduct(product){
if(product in getDefaultProducts()) {
return{
product: forSale.push(product),
checked: true
};
};
return {product};
}
console.log(useProduct("Laptop"))
console.log(forSale)
returns
[ { name: 'Laptop', checked: false },
{ name: 'Tablet', checked: false },
{ name: 'Phone', checked: false },
{ name: 'Ram', checked: false },
{ name: 'SSD', checked: false },
{ name: 'RasberyPi', checked: false },
{ name: 'Desktop', checked: false },
{ name: 'TV', checked: false },
{ name: 'Monitor', checked: false } ]
{ product: 'Laptop' }
[]
Should return:
[ { name: 'Laptop', checked: false },
{ name: 'Tablet', checked: false },
{ name: 'Phone', checked: false },
{ name: 'Ram', checked: false },
{ name: 'SSD', checked: false },
{ name: 'RasberyPi', checked: false },
{ name: 'Desktop', checked: false },
{ name: 'TV', checked: false },
{ name: 'Monitor', checked: false } ]
{ product: 'Laptop' }
[{name:"Laptop", checked: true}]
In the part where you checked the condition as if product in getDefaultProducts () will not work since getDefaultProducts is an array of objects. You are comparing strings with each object such as:
"Laptop" === { name: "Laptop", checked: false }
which will return false always. Instead you can use find function:
function useProduct(product){
getDefaultProducts().find(el => {
if (el.name === product) {
el.checked = true
forSale.push(el)
}
});
return product;
}
Try with this:
function useProduct(product){
const found = getDefaultProducts().find(p => p.name === product)
if (found) {
found.checked = true
forSale.push(found)
}
return {product}
}

Transform Nested Object Data Structure into an Array of Objects- JavaScript

I am having trouble with this problem taking an object and reformatting it to a new data structure. I need to take the beginning object and do the following: sort by group first, then label and exclude "active: false" records.
var beginning = {
Sister: {
1: { id: 1, name: 'Jesse Steven', active: false },
2: { id: 2, name: 'Zena Wong', active: true },
3: { id: 3, name: 'Katie Johnson', active: true },
},
Brother: {
10: { id: 10, name: 'Jeff Jacobs', active: true },
11: { id: 11, name: 'Mark Matha', active: false },
12: { id: 12, name: 'Kyle Ford', active: true },
},
Friend: {
20: { id: 20, name: 'Jim Dobbs', active: true },
}
};
After, it should looks like this:
var final = [
{ label: 'Jeff Jacobs', value: 10, group: 'Brother' },
{ label: 'Kyle Ford', value: 12, group: 'Brother' },
{ label: 'Jim Dobbs', value: 20, group: 'Friend' },
{ label: 'Katie Johnson', value: 3, group: 'Sister' },
{ label: 'Zena Wong', value: 2, group: 'Sister' }
];
Like this?
It's still missing a sort, but that can be easily remedied.
let beginning = {
Sister: {
1: { id: 1, name: 'Jesse Steven', active: false },
2: { id: 2, name: 'Zena Wong', active: true },
3: { id: 3, name: 'Katie Johnson', active: true },
},
Brother: {
10: { id: 10, name: 'Jeff Jacobs', active: true },
11: { id: 11, name: 'Mark Matha', active: false },
12: { id: 12, name: 'Kyle Ford', active: true },
},
Friend: {
20: { id: 20, name: 'Jim Dobbs', active: true },
}
};
let relations = Object.keys(beginning)
let final = relations.map(function(relation){
let num_keys = Object.keys(beginning[relation])
return num_keys.map(function(num_key){
beginning[relation][num_key]["group"] = relation
return beginning[relation][num_key]
})
})
.reduce(function(a, b){//flattens the returned array of arrays
return a.concat(b);
})
.filter(function(a){//filters out only active
return a["active"]
})
.map(function(a){//clean up some data
return {
label: a["name"],
value: a["id"],
group: a["group"]
}
})
console.log(final)
EDIT: Added sorting as the initial requirements asked for.
You can do this a number of ways, including for / in loops or some fancy stuff with ES2015, but a relatively simple functional example solution would be the following:
var activePeople = Object.keys(beginning).map(person => {
return Object.keys(beginning[person]).map(num => {
return (!!beginning[person][num].active) ? {
label: beginning[person][num].name,
value: beginning[person][num].id,
group: person
} : null
}).filter(i => !!i)
})
// flatten nested arrays
var final = [].concat.apply([], activePeople).sort((p1, p2) => {
if (p1.group < p2.group) {
return -1
} else if (p1.group > p2.group) {
return 1
}
if (p1.label < p2.label) {
return -1
}
return 1
})
I can propose faster one code:
"use strict";
let beginning = {
Sister: {
1: { id: 1, name: 'Jesse Steven', active: false },
2: { id: 2, name: 'Zena Wong', active: true },
3: { id: 3, name: 'Katie Johnson', active: true },
},
Brother: {
10: { id: 10, name: 'Jeff Jacobs', active: true },
11: { id: 11, name: 'Mark Matha', active: false },
12: { id: 12, name: 'Kyle Ford', active: true },
},
Friend: {
20: { id: 20, name: 'Jim Dobbs', active: true },
}
};
let groups = Object.keys(beginning).sort();
let final = [];
for (let i = 0, max = groups.length; i < max; i++) {
let keys = Object.keys(beginning[groups[i]]);
for (let j = 0, max2 = keys.length; j < max2; j++) {
let item = beginning[groups[i]][keys[j]];
if (item['active'] ) {
final.push({
label: item['name'],
value: keys[j],
group: groups[i]
});
}
}
}
console.log(final);

Categories

Resources