Combining two arrays based on properties - javascript

I have two arrays,
let student = [{ id: "weqwe", name: "john" }, { id: "wqeqweq", name: "doe" }]
let details = [
{ id: "2qweqweq", name: "larry", oName: "john" },
{ id: "231234qa", name: "jacob", oName: "john" },
{ id: "wetyrqwte", name: "jane", oName: "doe" }
]
I need to check through each object in details array and compare it with student array (compare with oName property in details array with name property in student array) and need to add an array of the details as on object property. Also need to remove the oName, I have tried in es6 but dynamically creating array and pushing gives only the last value, Please see the below expected output,
let output = [
{
id: "weqwe",
name: "john",
details: [
{ id: "2qweqweq", name: "larry" },
{ id: "231234qa", name: "jacob" }
]
},
{
id: "wqeqweq",
name: "doe",
details: [
{ id: "wetyrqwte", name: "jane" }
]
}
]
Thanks in advance !!

try this:
let student = [{ id: "weqwe", name: "john" }, { id: "wqeqweq", name: "doe" }]
let details = [
{ id: "2qweqweq", name: "larry", oName: "john" },
{ id: "231234qa", name: "jacob", oName: "john" },
{ id: "wetyrqwte", name: "jane", oName: "doe" }
];
let output = [{
id: "weqwe",
name: "john",
details: [
{ id: "2qweqweq", name: "larry" },
{ id: "231234qa", name: "jacob" }
]
},
{
id: "wqeqweq",
name: "doe",
details: [
{ id: "wetyrqwte", name: "jane" }
]
}
];
let result = student.map((obj) => {
obj.details = details.filter(o => o.oName === obj.name).map(({oName,...other}) =>other);
return obj;
});
console.log(result);

let student = [{id:"weqwe", name:"john"}, {id:"wqeqweq", name:"doe"}]
let details = [
{id:"2qweqweq", name:"larry", oName:"john"},
{id:"231234qa", name:"jacob", oName:"john"},
{id:"wetyrqwte", name:"jane", oName:"doe"}
]
let output= student.map(student=> {
const detailsObj = details.filter(({oName})=> oName === student.name)
return {...student, details: detailsObj.map(({oName, ...other})=> other)}
})
console.log(output)

Related

How to count the properties of an array of objects in JavaScript

var employees = [
{ name: "Josh", title: "receptionist" },
{ name: "Naila", title: "receptionist" },
{ name: "Tom", title: "doctor" },
{ name: "Becky", title: "doctor" }
];
For example on this one I would like to return
{
'doctor':2,
'receptionist':2
}
This is what I have tried:
const convert = (employees) => {
const res = {};
employees.forEach((employee) => {
const key = `${employee.title}${employee["doctor-receptionist"]}`;
if (!res[key]) {
res[key] = {...employee, count: 0 };
};
res[key].count += 1;
});
return Object.values(res);
};
console.log(convert(employees));
It returns the name of the employees, which I did not want.
I also thought about creating arrays for each kind of job title and filtering each employee from the employee array, and pushing them to their respective arrays. But I feel like there must be an easier way.
Array#reduce is the way to go:
const employees = [ { name: "Josh", title: "receptionist" }, { name: "Naila", title: "receptionist" }, { name: "Tom", title: "doctor" }, { name: "Becky", title: "doctor" } ],
summary = employees
.reduce((acc,{title}) => ({...acc,[title]:(acc[title] || 0) + 1}),{});
console.log( summary );
Just using reduce() can do it
var employees = [
{ name: "Josh", title: "receptionist" },
{ name: "Naila", title: "receptionist" },
{ name: "Tom", title: "doctor" },
{ name: "Becky", title: "doctor" }
];
let result = employees.reduce((a,c) =>{
a[c.title] = a[c.title] ? a[c.title] + 1 : 1
return a
},{})
console.log(result)
The reduce iterator was built for this kind of thing.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/reduce
I also employ Object.values() since the way I am using reduce is to create an object to easily keep track of the data along the way. The object.values helps distill that into an array when done.
const employees = [
{ name: "Josh", title: "receptionist" },
{ name: "Naila", title: "receptionist" },
{ name: "Tom", title: "doctor" },
{ name: "Becky", title: "doctor" }];
const reduced = Object.values(employees.reduce((b,a) => {
if (!b[a.title]) b[a.title] = {title: a.title, count: 1}
else b[a.title].count++;
return b
},{}))
console.log(reduced);
you can try this on your code
const employees = [
{ name: "Josh", title: "receptionist" },
{ name: "Naila", title: "receptionist" },
{ name: "Tom", title: "doctor" },
{ name: "Becky", title: "doctor" }
]
const sumReceptionist = employees.filter((item)=>{
return item.title === 'receptionist'
}).length
const sumDoctor = employees.filter((item)=>{
return item.title === 'doctor'
}).length
let total =
{
receptionist: sumReceptionist,
doctor: sumDoctor
}
console.log(total)
I think this is what you're trying to do. You want the total of the positions from the employee list?
const Employees = [{
name: "Josh",
title: "receptionist"
},
{
name: "Naila",
title: "receptionist"
},
{
name: "Tom",
title: "doctor"
},
{
name: "Becky",
title: "doctor"
},
{
name: "Chad",
title: "doctor"
},
{
name: "Cindy",
title: "nurse"
}
];
// A forEach won't return an object or array, so we create one to modify within it
const PositionTotals = {};
Employees.forEach(employee => {
// Check if property exists. If not, create it and add one to it before continuing loop
if (!PositionTotals.hasOwnProperty(employee.title))
return PositionTotals[employee.title] = 1;
PositionTotals[employee.title]++;
})
console.log(PositionTotals);
$('#PositionTotals').html(JSON.stringify(PositionTotals, null, '\t'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/1.2.3/jquery.min.js"></script>
<pre id="PositionTotals"></pre>

Filter out array using another array of objects

I am having two arrays
const selected = [];
const current = [
{ id: 1, name: "abc" },
{ id: 2, name: "def" }
];
const result = []
I need to compare these two arrays and the result should only have the single entry instead of duplicates. In the above example result should have the following output.
Also items in the selected should be taken into consideration and should be in the beginning of the result
result = [
{ id: 1, name: "abc" },
{ id: 2, name: "def" }
];
Also when the input is following
const selected = [ {id:5, name: "xyz" }];
const current = [
{ id: 1, name: "abc" },
{ id: 2, name: "def" }
];
result = [[
{ id: 5, name: "xyz" },
{ id: 1, name: "abc" },
{ id: 2, name: "def" }
];
Also when the input is following
const selected = [ {id:1, name: "abc" }, {id:4, name: "lmn" }];
const current = [
{ id: 1, name: "abc" },
{ id: 2, name: "def" }
];
result = [[
{ id: 1, name: "abc" },
{ id: 4, name: "lmn" }
{ id: 2, name: "def" }
];
Note the comparison should be made using name field
Code that I tried
const res = [...(selected || [])].filter((s) =>
current.find((c) => s.name === c.name)
);
Sandbox: https://codesandbox.io/s/nervous-shannon-j1vn5k?file=/src/index.js:115-206
You could get all items and filter the array by checking the name with a Set.
const
filterBy = (key, s = new Set) => o => !s.has(o[key]) && s.add(o[key]),
selected = [{ id: 1, name: "abc" }, { id: 1, name: "lmn" }],
current = [{ id: 1, name: "abc" }, { id: 2, name: "def" }],
result = [...selected, ...current].filter(filterBy('name'));
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
Loop through selected, and if there is no object in current with a name that matches the name of the object in the current iteration push it into current.
const selected=[{id:1,name:"abc"},{id:6,name:"def"},{id:4,name:"lmn"}];
const current=[{id:1,name:"abc"},{id:2,name:"def"}];
for (const sel of selected) {
const found = current.find(cur => cur.name === sel.name);
if (!found) current.push(sel);
}
console.log(current);
This is a good use for .reduce, avoids multiple loops/finds and doesn't need filtering with side-effects.
const selected = [ {id:1, name: "abc" }, {id:4, name: "lmn" }];
const current = [
{ id: 1, name: "abc" },
{ id: 2, name: "def" }
];
const result = Object.values(
[...selected, ...current].reduce((obj, item) => {
obj[item.name] = obj[item.name] || item;
return obj;
}, {})
)
console.log(result);

get keys from the nested array of objects

I am looking for a function that can mutate my data i.e array of object with a nested object. It will include keys that have object/array values (it should only include keys with immediate string/number/boolean values).
Example
[
{
id: 1,
person1: {
firstname: "test1",
lastname: 'singh',
address: {
state: "maharashtra",
}
}
},
{
id: 2,
person2: {
firstname: "test2",
lastname: 'rathod',
address: {
state: "kerala",
}
}
},
{
id: 3,
person3: {
firstname: "test3",
lastname: 'gokale',
address: {
state: "Tamilnadu",
}
}
}
]
Expected output
[
{
title: 'person1',
value: 'person.id'
},
{
title: 'person1',
value: 'person.firstname'
},
{
title: 'person1',
value: 'person.lastname'
},
{
title: 'person1',
value: 'person.address'
},
{
title: 'person1',
value: 'person.address.state'
},
...sameforOthers
]
Basically, I need a function that will get an array and will return an array of objects as a given above as expected output
Thanks in advance
I have come up with a solution. below is the link for code sandbox for the
https://codesandbox.io/s/heuristic-rubin-yy2cyy?file=/src/index.js:0-213same
const suggestions = [
{
id: 1,
person1: {
id: "1",
firstname: "test1",
lastname: "singh",
address: {
state: "maharashtra"
},
attributeId: "fhgfgh"
}
}
];
const typeList = ["string", "number", "boolean"];
const getLabelValue = (itemList, initalArr, parentId) => {
if (Array.isArray(itemList)) {
itemList.forEach((currentItem, idx) => {
const id = parentId ? `${parentId}.${idx}` : idx;
if (typeList.includes(typeof currentItem)) {
initalArr.push({
title: id,
value: id
});
} else {
getLabelValue(currentItem, initalArr, id);
}
});
} else {
let keys = Object.keys(itemList);
keys.forEach((currentKey) => {
let currentItem = itemList[currentKey];
const id = parentId ? `${parentId}.${currentKey}` : currentKey;
if (typeList.includes(typeof currentItem)) {
initalArr.push({
title: id,
value: id
});
} else {
getLabelValue(currentItem, initalArr, id);
}
});
}
return initalArr;
};
console.log(">>>>>>>>>", getLabelValue(suggestions, [], ""));

Find synced users from two arrays based on id and return array A with one column from array B

i am trying to find a list of synced users between two arrays (objArray1 & objArray2) and return the data from objArray1 along with 'aid' in Objarray2. I have the below code working, but i am trying to see if can return 'aid' from objArray2 as well in the below format.
Code sample below
// SystemA
const objArray1 = [
{ id: "1", name: "John" },
{ id: "2", name: "Jack" },
{ id: "3", name: "Sam" },
{ id: "4", name: "Bill" },
];
// SystemB
const objArray2 = [
{ id: "1", name: "John", aid:"uuud2905555" },
{ id: "3", name: "Sam" }, aid:"uuud29029303"
{ id: "5", name: "Bob" }, aid:"uuud29435454"
];
const array1IDs = objArray1.map((item) => {
return item.id
})
// Result: array1IDs = ["1", "2", "3", "4"];
const array2IDs = objArray2.map((item) => {
return item.id
})
// Result: array2IDs = ["1", "3", "5"];
// FIND SYNCED USERS
// Compare the id value of each item in objArray1 with each item of objArray2
// Return the ones that match.
const syncedUsers = objArray1.filter((item) => {
const found = objArray2.find((element) => element.id === item.id);
return found;
});
Required JSON Format, please note that all matching items should be returned from objArray1, with the exception of 'aid' from objArray2
{
"records": [
{
"id": {aid}, // from objArray2
"fields": {
"Name":{name}, // from objArray1
"sid": {id} // from objArray1
}
]
}
Presented below is one possible way to achieve the desired objective.
Code Snippet
// method to create result as "JSON"
const createJSON = (arr1, arr2) => (
// use "stringify" to transform JavaScript object into JSON
JSON.stringify({
// set-up the "records" prop
records: arr2
.filter( // filter to keep only those that have matching "id"
({ id }) => arr1.some(ob => ob.id === id)
)
.map( // de-structure & rename props to match desired objective
({ id : sid, name : Name, aid: id }) => ({
id,
fields: {Name, sid}
})
)
})
);
// SystemA
const objArray1 = [
{ id: "1", name: "John" },
{ id: "2", name: "Jack" },
{ id: "3", name: "Sam" },
{ id: "4", name: "Bill" },
];
// SystemB
const objArray2 = [
{ id: "1", name: "John", aid:"uuud2905555" },
{ id: "3", name: "Sam", aid:"uuud29029303" },
{ id: "5", name: "Bob", aid:"uuud29435454" },
];
console.log('result as a JSON: ', createJSON(objArray1, objArray2));
.as-console-wrapper { max-height: 100% !important; top: 0 }
Explanation
Inline comments added to the snippet above.
EDIT
Use name and id from array-1. Used restOfArr1Props to account for all other props of array-1 objects to be included.
const createJSON = (arr1, arr2) => (
JSON.stringify({
records: arr1
.filter(
({ id }) => arr2.some(ob => ob.id === id)
)
.map(
({ id : sid, name : Name, ...restOfArr1Props }) => ({
id: arr2.find(a2 => a2.id === sid)?.aid ?? 'missing aid',
fields: {
Name, sid, ...restOfArr1Props
},
})
)
})
);
// SystemA
const objArray1 = [
{ id: "1", name: "John", prop1: 'value11', prop2: 'value12' },
{ id: "2", name: "Jack", prop1: 'value21', prop2: 'value22' },
{ id: "3", name: "Sam", prop1: 'value31', prop2: 'value32' },
{ id: "4", name: "Bill", prop1: 'value41', prop2: 'value42' },
];
// SystemB
const objArray2 = [
{ id: "1", name: "John", aid:"uuud2905555" },
{ id: "3", name: "Sam", aid:"uuud29029303" },
{ id: "5", name: "Bob", aid:"uuud29435454" },
];
console.log('result as a JSON: ', createJSON(objArray1, objArray2));
.as-console-wrapper { max-height: 100% !important; top: 0 }
const objArray1 = [
{ id: '1', name: 'John', type: 'bully' },
{ id: '2', name: 'Jack', type: 'sporty' },
{ id: '3', name: 'Sam', type: 'kind' },
{ id: '4', name: 'Bill', type: 'poliet' },
];
const objArray2 = [
{ id: '1', name: 'John', aid: 'uuud2905555' },
{ id: '3', name: 'Sam', aid: 'uuud29029303' },
{ id: '5', name: 'Bob', aid: 'uuud29435454' },
];
const syncedUsers = { records: [] };
for (let user1 of objArray1) {
const foundUser = objArray2.find(user2 => user2.id === user1.id);
if (foundUser) {
syncedUsers.records.push({
id: foundUser.aid,
fields: { sid: user1.id, name: user1.name, ...user1 },
});
}
}
console.log(JSON.stringify(syncedUsers));

mapping two arrays of equivalent length by object attributes javascript [duplicate]

This question already has answers here:
Merge two array of objects based on a key
(23 answers)
Closed 1 year ago.
I have two arrays:
Array 1:
[
{
name: 'Bob',
traits: {
id: 1
}
}, {
name: 'Karl',
traits: {
id: 2
}
}, {
name: 'Joseph',
traits: {
id: 3
}
}
]
Array 2:
[
{
name: 'Karl',
user_id: 2,
dog: 'Rottweiler'
}, {
name: 'Joseph',
user_id: 3,
dog: 'Poodle'
}, {
name: 'Bob',
user_id: 1,
dog: 'Puppy'
}
]
Desired outcome:
I want to be able to merge the second array into the first array by finding what element user_id matches with id and then adding the object to array.
For example:
array 1 obj
{
name: 'Bob',
traits: {
id: 1
}
}
Since the id matches with array 2 obj user_id:
{
name: 'Bob',
user_id: 1,
dog: 'Puppy'
}
Final outcome will be:
{
name: 'Bob',
traits: {
name: 'Bob',
user_id: 1,
dog: 'Puppy'
}
}
arr2.forEach((obj) => {
const idx = arr1.findIndex((o) => o.traits.id === obj.user_id);
if (idx !== -1) {
arr1[idx] = { ...arr1[idx], traits: { ...obj } }
}
})
console.log(arr1[0]) // { name: 'Bob', traits: { name: 'Bob', user_id: 1, dog: 'Puppy' } }
Turn the second array into a map keyed by user_id, and then iterate the first array. Find the corresponding object in the map, and spread the matching object value into the traits property:
let arr1 = [{name: 'Bob',traits: {id: 1}},{name: 'Karl',traits: {id: 2}},{name: 'Joseph',traits: {id: 3}}];
let arr2 = [{name: 'Karl', user_id: 2,dog: 'Rottweiler'},{name: 'Joseph', user_id: 3,dog: 'Poodle'},{name: 'Bob',user_id: 1,dog: 'Puppy'}];
let map = new Map(arr2.map(item => [item.user_id, item]));
let result = arr1.map(item => {
let traits = map.get(item.traits.id);
return traits ? { ...item, traits} : item;
});
console.log(result);
As lookup in a map has an amortised time complexity of O(1), this is more efficient than finding the key in the array on every iteration (like with calling find).
You can easily achieve this result using map and find. Just map over the first array and find the element with obj.traits.id in the arr2. then return the desired result.
const arr1 = [
{
name: "Bob",
traits: {
id: 1,
},
},
{
name: "Karl",
traits: {
id: 2,
},
},
{
name: "Joseph",
traits: {
id: 3,
},
},
];
const arr2 = [
{
name: "Karl",
user_id: 2,
dog: "Rottweiler",
},
{
name: "Joseph",
user_id: 3,
dog: "Poodle",
},
{
name: "Bob",
user_id: 1,
dog: "Puppy",
},
];
const result = arr1.map((obj) => {
const { name, traits } = obj;
const isExist = arr2.find((o) => o.user_id === traits.id);
if (isExist) {
return { name, traits: { ...isExist } };
}
return obj;
});
console.log(result);
let a = [
{
name: 'Bob',
traits: {
id: 1
}
}, {
name: 'Karl',
traits: {
id: 2
}
}, {
name: 'Joseph',
traits: {
id: 3
}
}
];
let b = [
{
name: 'Karl',
user_id: 2,
dog: 'Rottweiler'
}, {
name: 'Joseph',
user_id: 3,
dog: 'Poodle'
}, {
name: 'Bob',
user_id: 1,
dog: 'Puppy'
}
];
a.map(aobj =>{
let sameIdObj = b.find( bobj => bobj.user_id === aobj.traits.id )
sameIdObj && (aobj.traits = sameIdObj)
})
console.log(a);

Categories

Resources