JS - merge 2 arrays based on properties - javascript

I'm trying to merge 2 arrays of objects where the resulting array should have only objects present in array 1 (selectedNames) but with one property from corresponding objects from array 2 (nameDetails). There's one matching (unique) property to match them:
const selectedNames = [
{
id: '11'
name: 'joe',
},
{
id: '22',
name: 'bill',
},
];
const nameDetails = [
{
nameId: '11',
salary: '23422',
location: 'New Jersey',
},
{
nameId: '33',
salary: '23424',
location: 'New York',
},
{
nameId: '22',
salary: '99999',
location: 'Boston',
},
{ nameId: '44',
salary: '323232',
location: 'Chicago',
},
];
The matching property is selectedNames.id === nameDetails.nameId. All entries in selectedNames will definitely be present in nameDetails (but not the other way round). The resulting array should look like that:
[
{
id: '11',
name: 'joe',
salary: '23422',
},
{
id: '22',
name: 'bill',
salary: '99999'
}
]
I'm a bit confused. I know it'll probably consist of .includes() and filter() and ... for merging? I'm not sure how to handle it.
Alternatively, which will probably be much easier, filter the nameDetails array to have only objects with nameId that exists (as id) in selectedNames.

I am a bit confused by your example result. For example where does id: '11111' come from?
Are you looking for something like this maybe?
const selectedNames = [
{
id: '11',
name: 'joe',
},
{
id: '22',
name: 'bill',
},
];
const nameDetails = [
{
nameId: '11',
salary: '23422',
location: 'New Jersey',
},
{
nameId: '33',
salary: '23424',
location: 'New York',
},
{
nameId: '22',
salary: '99999',
location: 'Boston',
},
{ nameId: '44',
salary: '323232',
location: 'Chicago',
},
];
const merged = selectedNames.map(n => {
n.salary = nameDetails.filter(d => n.id === d.nameId)[0].salary;
return n;
});
console.log(merged)
Note: This will change the original selectedNames by adding the salary from the corresponding entry in nameDetails.

Maybe this fits your needs:
selectedNames.map(({ id, name }) => {
let salary = nameDetails.find((nameItem) => nameItem.nameId === id).salary;
return { id, name, salary };
})
Will result in:
[
{
id: '11',
name: 'joe',
salary: '23422',
},
{
id: '22',
name: 'bill',
salary: '99999',
}
]

Related

React - How to get specific array of object value based on another set of array elements

I want to get the specific array value and its content based on other array values.
Here's my first array
const array1 = ['John', 'Mary', 'John', 'Kurt']
Here's the other array of object
const players = [
{
name: 'Kurt',
sport: 'Basketball',
},
{
name: 'Harry',
sport: 'Badminton',
},
{
name: 'Mary',
sport: 'Volleyball',
},
{
name: 'John',
sport: 'Swimming',
},
{
name: 'Peter',
sport: 'Basketball',
},
{
name: 'John',
sport: 'Tennis',
},];
What I wanted to happen is, If John in array1 matches the name in players array it will return the sport.
const array1 = ['John', 'Mary', 'John1', 'Kurt1']
const players = [
{
name: 'Kurt',
sport: 'Basketball',
},
{
name: 'Harry',
sport: 'Badminton',
},
{
name: 'Mary',
sport: 'Volleyball',
},
{
name: 'John',
sport: 'Swimming',
},
{
name: 'Peter',
sport: 'Basketball',
},
{
name: 'John',
sport: 'Tennis',
},];
let result=[]
for(let i=0;i<array1.length;i++){
result.push(...players.filter((el,j) => el.name===array1[i]));
//store j to get element position
}
console.log(result)
you can use the filter() and map() methods to filter the original array based on the criteria specified in the second array
const selectedArray = players.filter(item => array1.includes(item.name))
.map(item => ({
name: item.name,
sport: item.sport,
}));

How does one, from an array of objects, collect and aggregate the merged variant of all objects with a specific equal property value?

const portfolio = [
{ name: 'Mark', stock: 'FB' },
{ name: 'Steve', stock: 'AAPL' },
{ name: 'Tim', stock: 'AAPL' },
{ name: 'Steve', stock: 'MSFT' },
{ name: 'Bill', stock: 'MSFT' },
{ name: 'Bill', stock: 'AAPL' },
];
// Output
const shareholder = [
{ stock: 'AAPL', name: ['Steve', 'Bill', 'Tim'], count: 3 },
{ stock: 'MSFT', name: ['Steve', 'Bill'], count: 2 },
{ stock: 'FB', name: ['Mark'], count: 1 },
];
if I create one function which take input array as param and this will return output array in jS
One way using reduce and Object.values
const portfolio = [{
name: 'Mark',
stock: 'FB'
},
{
name: 'Steve',
stock: 'AAPL'
},
{
name: 'Tim',
stock: 'AAPL'
},
{
name: 'Steve',
stock: 'MSFT'
},
{
name: 'Bill',
stock: 'MSFT'
},
{
name: 'Bill',
stock: 'AAPL'
},
];
const result = Object.values(portfolio.reduce((res, {
stock,
name
}) => {
const existing = res[stock] || {
stock,
names: [],
count: 0
}
res[stock] = {
stock,
names: [...existing.names, name],
count: existing.count + 1
}
return res
}, {}))
console.log(result)
From the above comment ...
"What the OP wants is filtering and grouping array items (by a specific key) together with value aggregation of some/one other key/s. One usually would use a reduce based approach. One question though ... what is the additional count value good for when one has this information already in any item's item.name.length (or at least rename count to nameCount)."
... used techniques/methods ...
Object.values
Array.prototype.reduce
Array.prototype.sort
Destructuring Assignment / object destructuring
Logical nullish assignment operator / ??=
const portfolio = [
{ name: 'Mark', stock: 'FB' },
{ name: 'Steve', stock: 'AAPL' },
{ name: 'Tim', stock: 'AAPL' },
{ name: 'Steve', stock: 'MSFT' },
{ name: 'Bill', stock: 'MSFT' },
{ name: 'Bill', stock: 'AAPL' },
];
const shareholderList = Object.values( // get only the values from ...
// ... create an index/map of stock specific shareholder items/objects
portfolio.reduce((stockIndex, { name, stock }) => {
// access an already existing object or
// create a new grouped (by `stock` value) to be merged and aggregated object.
const groupedMerger = (stockIndex[stock] ??= { stock, names: [], nameCount: 0 });
// aggregate list of `stock` specific shareholder names.
groupedMerger.names.push(name);
// increment count of `stock` specific shareholder names.
++groupedMerger.nameCount;
// the programmatically built index/map of stock specific shareholder items/objects.
return stockIndex;
}, {})
).sort((a, b) => b.nameCount - a.nameCount); // sort shareholder items by theirs `nameCount`s.
console.log({ shareholderList });
.as-console-wrapper { min-height: 100%!important; top: 0; }
And in order to demonstrate how each part works and how everything works together, the above main approach will be compacted into a (re-usable) function statement.
function aggregateStockIndex(index, { name, stock }) {
const groupedMerger = (index[stock] ??= { stock, names: [], nameCount: 0 });
groupedMerger.names.push(name);
++groupedMerger.nameCount;
return index;
}
const portfolio = [
{ name: 'Mark', stock: 'FB' },
{ name: 'Steve', stock: 'AAPL' },
{ name: 'Tim', stock: 'AAPL' },
{ name: 'Steve', stock: 'MSFT' },
{ name: 'Bill', stock: 'MSFT' },
{ name: 'Bill', stock: 'AAPL' },
];
const stockIndex = portfolio
.reduce(aggregateStockIndex, {});
const shareholderList = Object.values(
// stockIndex
portfolio.reduce(aggregateStockIndex, {})
).sort((a, b) => b.nameCount - a.nameCount);
console.log({
stockIndex,
shareholderList,
});
.as-console-wrapper { min-height: 100%!important; top: 0; }
I shared a function named groupPortfolio that takes a portfolio as an argument expecting to be a list of people holding a share of a stock.
The function first groups those people as a map binding each stock to which holders it belong to and eventually uses that map to create the final array as a list of stocks where each one has a list of people holding its share and the corresponding amount of people in that list.
function groupPortfolio(portfolio){
//groups the portfolio item in [stock] => shareholders[]
let grouped = {};
for(let o of portfolio){
if( !Object.keys(grouped).includes(o.stock) )
grouped[o.stock] = [];
grouped[o.stock].push( o.name );
}
//creates the shareholders array starting from the grouped stocks
let shareholders = [];
for( let stockGroup of Object.keys(grouped) ){
shareholders.push(
{ stock: stockGroup, name: grouped[stockGroup], count: grouped[stockGroup].length }
);
}
return shareholders;
}
const portfolio1 = [
{name: 'Mark', stock: 'FB'},
{name: 'Steve', stock: 'AAPL'},
{name: 'Tim', stock: 'AAPL'},
{name: 'Steve', stock: 'MSFT'},
{name: 'Bill', stock: 'MSFT'},
{name: 'Bill', stock: 'AAPL'},
];
let shareholder1 = groupPortfolio(portfolio1);
console.log( shareholder1 );
/*
0:
stock: "FB"
name: ['Mark']
count: 1
1:
stock: "AAPL"
name: (3) ['Steve', 'Tim', 'Bill']
count: 3
2:
stock: "MSFT"
name: (2) ['Steve', 'Bill']
count: 2
*/
You can use two simple for loops to convert the first array into the second array.
Working Example:
const portfolio = [
{name: 'Mark', stock: 'FB'},
{name: 'Steve', stock: 'AAPL'},
{name: 'Tim', stock: 'AAPL'},
{name: 'Steve', stock: 'MSFT'},
{name: 'Bill', stock: 'MSFT'},
{name: 'Bill', stock: 'AAPL'},
];
let shareholder = [];
// CYCLE THROUGH PORTFOLIO
for (let i = 0; i < portfolio.length; i++) {
// DETERMINE IF STOCK ENTRY ALREADY EXISTS
let stockIndex = shareholder.length;
for (let j = 0; j < shareholder.length; j++) {
if (portfolio[i].stock === shareholder[j].stock) {
stockIndex = j;
}
}
// ADD NEW ENTRY IF STOCK ENTRY DOES NOT EXIST
if (stockIndex === shareholder.length) {
shareholder[stockIndex] = {stock: portfolio[i].stock, name: [], count: 0};
}
// ADD DETAILS TO NEW OR EXISTING STOCK ENTRY
shareholder[stockIndex].name.push(portfolio[i].name);
shareholder[stockIndex].count++;
}
console.log(shareholder);
You could achieve this in two steps
First create an object with stock as the key name to find out all the records with unique stock.
Loop over the object created in step#1 to convert to an Array structure
I couldn't think of ay solution which could achieve it in single iteration.
Please see the code snippet below.
const portfolio = [
{name: 'Mark', stock: 'FB'},
{name: 'Steve', stock: 'AAPL'},
{name: 'Tim', stock: 'AAPL'},
{name: 'Steve', stock: 'MSFT'},
{name: 'Bill', stock: 'MSFT'},
{name: 'Bill', stock: 'AAPL'},
];
let shareholderObj = {};
let shareholderArr = [];
portfolio.forEach((el) => {
const stock = el.stock
if(shareholderObj[stock]){
shareholderObj[stock].name.push(el.name)
}
else{
shareholderObj[stock] = {
name: [el.name]
}
}
})
for (let [key, value] of Object.entries(shareholderObj)) {
shareholderArr.push({
stock: key,
name: value.name,
count: value.name.length
})
}
console.log(shareholderArr)
A simplified approach by taking the new length of name as count.
const portfolio = [{ name: 'Mark', stock: 'FB' }, { name: 'Steve', stock: 'AAPL' }, { name: 'Tim', stock: 'AAPL' }, { name: 'Steve', stock: 'MSFT' }, { name: 'Bill', stock: 'MSFT' }, { name: 'Bill', stock: 'AAPL' }],
shareholder = Object
.values(portfolio.reduce((r, { name, stock }) => {
r[stock] ??= { stock, name: [] };
r[stock].count = r[stock].name.push(name);
return r;
}, {}))
.sort((a, b) => b.count - a.count)
console.log(shareholder);
.as-console-wrapper { max-height: 100% !important; top: 0; }

Algorithm for diffing two deeply nested JavaScript objects that can identify insertions and moves by ID

I'm looking for pointers on how to approach diffing two nested objects with some semantic awareness. As an example, take an object that represents a company org chart. Each employee has some properties about them like their role and salary, as well as an "employees" array which contains any employees that report to them
const employees = [
{
employee: 'John',
employeeId: '1',
roleDetails: {
title: 'CEO',
compensation: {
bonus: 10000,
salary: 899999
}
},
employees: [
{
employee: 'Will',
employeeId: '4',
roleDetails: {
title: 'Assistant to CEO',
compensation: {
bonus: 9919,
salary: 17728
}
},
employees: []
},
{
employee: 'Jane',
employeeId: '5',
roleDetails: {
title: 'Head of Operations',
compensation: {
bonus: 8190,
salary: 17492
}
},
employees: [
{
employee: 'Tom',
employeeId: '6',
roleDetails: {
title: 'Operations Specialist',
compensation: {
bonus: 1839,
salary: 18429
}
},
employees: []
},
{
employee: 'Patricia',
employeeId: '7',
roleDetails: {
title: 'Operations Specialist',
compensation: {
bonus: 1378,
salary: 15890
}
},
employees: []
},
]
},
]
},
{
employee: 'Ned',
employeeId: '2',
roleDetails: {
title: 'CMO',
compensation: {
bonus: 18293,
salary: 47291
}
},
employees: [
{
employee: 'Trent',
employeeId: '8',
roleDetails: {
title: 'Marketing Manager',
compensation: {
bonus: 10000,
salary: 129999
}
},
employees: [
{
employee: 'Harry',
employeeId: '9',
roleDetails: {
title: 'Marketing Associate',
compensation: {
bonus: 18492,
salary: 188929
}
},
employees: []
}
]
}
]
},
{
employee: 'Elsa',
employeeId: '3',
roleDetails: {
title: 'CFO',
compensation: {
bonus: 10000,
salary: 129999
}
},
employees: [
{
employee: 'Harry',
employeeId: '10',
roleDetails: {
title: 'Finance Associate',
compensation: {
bonus: 14829,
salary: 1492002
}
},
employees: []
}
]
}]
Let's imagine we take a snapshot of this company once and then again 3 months later. In between there, some employees have been added or removed, some have had salary increases or job title changes, and some have changed roles so they now report to different people.
How would I create a diff that can accurately identify these changes to summarize to users in a human readable way? I tried a basic text diff like this: http://jsfiddle.net/cs5d3uwn/ but it doesn't recognize that two employees with the same ID are the same, and that ID never changes. So if one employee replaces the other at the same position, it reports that some of the attributes of that employee changed, not that it's a remove and add.
The ideal output would be something I could use to summarize the differences in words, like this:
changes: [
{ employeeId: 10, name: "Lisa", path: "employees[0].employees[2].employees[0]", change: 'ADDED' }
{ employeeId: 6, name: "Tom", path: "employees[0].employees[1].employees[0]", change: 'REMOVED' }
{ employeeId: 4, name: "Ned", path: "employees[1]", change: 'UPDATED', key: 'salary', oldValue: 47291, newValue: 89399 },
{ employeeId: 7, name: "Harry", change: 'MOVED', oldPath: 'employees[1].employees[0].employees[0]', newPath: 'employees[1].employees[1]'}
{ employeeId: 7, name: "Harry", change: 'UPDATED', path: 'employees[1].employees[1].roleDetails.title', oldValue: 'Marketing Associate', newValue: 'Marketing Manager' }]
Any pointers on libraries to use or approaches to tackle the problem would be very appreciated.
The nested structure can be flattened without any loss of information by giving each employee a reportsTo property. This contains as much information as the "lineage" that the OP suggests.
Since reportsTo has a simple scalar value (the id of the employee this employee reports to), it's change over time can be represented just like a change to any other employee prop.
Another advantage is concision in what constitutes a change. If an employee's boss's boss's boss changes, that's a change in their lineage, but not really a change from an HR perspective (I would assert). That employee still reports to their same boss.
let flatArray = [];
function transformEmployee(employee, reportsTo) {
let result = Object.assign({}, employee);
delete result.employees;
result.reportsTo = reportsTo ? reportsTo.employeeId : null;
flatArray.push(result);
}
// invoke fn on every employee in the tree, depth-first
function traverse(employee, reportsTo, fn) {
if (employee.employeeId) fn(employee, reportsTo);
employee.employees.forEach(e => traverse(e, employee, fn));
}
const employee = getData();
traverse(employee, null, transformEmployee)
console.log(flatArray)
function getData() {
return {
employees: [{
employee: 'John',
employeeId: '1',
roleDetails: {
title: 'CEO',
compensation: {
bonus: 10000,
salary: 899999
}
},
employees: [{
employee: 'Will',
employeeId: '4',
roleDetails: {
title: 'Assistant to CEO',
compensation: {
bonus: 9919,
salary: 17728
}
},
employees: []
},
{
employee: 'Jane',
employeeId: '5',
roleDetails: {
title: 'Head of Operations',
compensation: {
bonus: 8190,
salary: 17492
}
},
employees: [{
employee: 'Tom',
employeeId: '6',
roleDetails: {
title: 'Operations Specialist',
compensation: {
bonus: 1839,
salary: 18429
}
},
employees: []
},
{
employee: 'Patricia',
employeeId: '7',
roleDetails: {
title: 'Operations Specialist',
compensation: {
bonus: 1378,
salary: 15890
}
},
employees: []
},
]
},
]
},
{
employee: 'Ned',
employeeId: '2',
roleDetails: {
title: 'CMO',
compensation: {
bonus: 18293,
salary: 47291
}
},
employees: [{
employee: 'Trent',
employeeId: '8',
roleDetails: {
title: 'Marketing Manager',
compensation: {
bonus: 10000,
salary: 129999
}
},
employees: [{
employee: 'Harry',
employeeId: '9',
roleDetails: {
title: 'Marketing Associate',
compensation: {
bonus: 18492,
salary: 188929
}
},
employees: []
}
]
}
]
},
{
employee: 'Elsa',
employeeId: '3',
roleDetails: {
title: 'CFO',
compensation: {
bonus: 10000,
salary: 129999
}
},
employees: [{
employee: 'Harry',
employeeId: '10',
roleDetails: {
title: 'Finance Associate',
compensation: {
bonus: 14829,
salary: 1492002
}
},
employees: []
}]
}
]
}
}
With that, we're ready to record differences between two arrays. We can produce three arrays: adds, drops, and diffs
adds and drops are straight-forward enough...
const oldEmployees = [ /* ... */];
const newEmployees = [ /* ... */];
// adds are employees in the new array not in the old array
const adds = newEmployees.filter(newE =>
!oldEmployees.find(oldE => oldE.employeeId === newE.employeeId));
// drops are employees in the old array not in the new array
const drops = oldEmployees.filter(newE =>
!newEmployees.find(oldE => oldE.employeeId === newE.employeeId));
That leaves diffs, which are employees (matched by ids) in both arrays but have had one or more value change. Here's a working demonstration of how to compare two objects with a fixed set of keys that are known a priori...
// compare two versions of an employee (with the same ids)
// create a diff object that describes differences
// this presumes a fixed set of keys, as the OP has
function compare(id, newE, oldE, diffs) {
const keyPaths = [['employee'], ['reportsTo'], ['roleDetails', 'title'], ['roleDetails', 'compensation', 'salary'], ['roleDetails', 'compensation', 'bonus']];
keyPaths.forEach(key => {
let newValue = valueAtPath(newE, key);
let oldValue = valueAtPath(oldE, key);
if (newValue !== oldValue) {
diffs.push({ id, key: key.join('.'), oldValue, newValue });
}
});
}
// get a value at a path in an object
function valueAtPath(object, path) {
if (path.length === 1) return object[path[0]];
return valueAtPath(object[path[0]], path.slice(1))
}
let oldElsa = {
employee: 'Elsa',
employeeId: '3',
reportsTo: '12',
roleDetails: {
title: 'Bookkeepper',
compensation: {
bonus: 1000,
salary: 60000
}
}
}
let newElsa = {
employee: 'Elsa',
employeeId: '3',
reportsTo: '2',
roleDetails: {
title: 'CFO',
compensation: {
bonus: 10000,
salary: 129999
}
}
}
let diffs = []
compare(3, newElsa, oldElsa, diffs);
console.log(diffs)
Given our old and new employee sets, we'd just run this diff process on all of them...
const oldEmployees = [ /* ... */];
const newEmployees = [ /* ... */];
let diffs = [];
newEmployees.forEach(newE => {
const id = newE.employeeId;
const oldE = oldEmployees.find(o => o.employeeId === id));
compare(id, newE, oldE, diffs);
});

Merge two array of objects based on matching properties

I've 2 arrays with partial information and I wish to merge those arrays with all the information into one array.
Array 1 :
const arr1 = [
{
name: 'Rohan',
surname: 'Mehra',
age: '15',
date: "2021-01-19",
location: 'Goa'
},
{
name: 'Aman',
surname: 'Kohli',
age: '14',
date: "2021-01-19",
location: 'Kolkata'
},
{
name: 'Sam',
surname: 'Sharma',
age: '16',
date: "2021-01-21",
location: 'Mumbai'
}
]
Array 2 :
const arr2 = [
{
rollNo: 1,
marks: 100,
name: 'Rohan',
date: "2021-01-19",
},
{
rollNo: 2,
marks: 90,
surname: 'Kohli',
date: "2021-01-19",
},
{
rollNo: 3,
marks: 70,
date: "2021-01-21",
ExamCenter: {
place: 'Mumbai'
}
}
]
I want to get a final array with the properties from both arrays. The Object keys sometimes change and I wanted to match the key with the other common key and merge them. But I am not able to proceed with the solution. Here is the result array I wish to get.
const final = [
{
name: 'Rohan',
surname: 'Mehra',
age: '15',
date: "2021-01-19",
location: 'Goa',
rollNo: 1,
marks: 100,
},
{
name: 'Aman',
surname: 'Kohli',
age: '14',
date: "2021-01-19",
location: 'Kolkata',
rollNo: 2,
marks: 90,
},
{
name: 'Sam',
surname: 'Sharma',
age: '16',
date: "2021-01-21",
location: 'Mumbai',
rollNo: 3,
marks: 70,
}
]
I'm trying with nested map loops but not able to proceed
const final = arr1.map((item,index) => {
arr2.map((innerItem, i) => {
if(item[Object.keys(innerItem)][index] === innerItem[Object.keys(innerItem)][0]){
console.log(item);
}
})
})
There is a mistake in your arr2. The surname for 2nd item should be kohli instead of kolhi. Anyway, You can do the following to merge two array based on dynamic matching attribute. What we are doing here is,
For each item of arr1 we are finding the keys using Object.keys method and checking which object from arr2 has maximum matching object with the item of arr1. Then we merge the two item together.
arr1 = [
{
name: 'Rohan',
surname: 'Mehra',
age: '15',
date: "2021-01-19",
location: 'Goa'
},
{
name: 'Aman',
surname: 'Kohli',
age: '14',
date: "2021-01-19",
location: 'Kolkata'
},
{
name: 'Sam',
surname: 'Sharma',
age: '16',
date: "2021-01-21",
location: 'Mumbai'
}
]
arr2 = [
{
rollNo: 1,
marks: 100,
name: 'Rohan',
date: "2021-01-19",
},
{
rollNo: 2,
marks: 90,
surname: 'Kohli',
date: "2021-01-19",
},
{
rollNo: 3,
marks: 70,
date: "2021-01-21",
ExamCenter: {
place: 'Mumbai'
}
}
]
res = arr1.map(item => {
keys1 = Object.keys(item);
let max = 0;
const temp = arr2.reduce((prev, item2) => {
maxTemp = keys1.filter(key => item[key] === item2[key]).length;
if(maxTemp > max) {
max = maxTemp;
prev = item2;
}
return prev;
}, {})
if(temp) {
return {...item, ...temp}
}
});
console.log(res);
You can do something like this to merge two arrays.
const arr1 = [
{
name: 'Rohan',
surname: 'Mehra',
age: '15',
date: "2021-01-19",
location: 'Goa'
},
{
name: 'Aman',
surname: 'Kohli',
age: '14',
date: "2021-01-19",
location: 'Kolkata'
},
{
name: 'Sam',
surname: 'Sharma',
age: '16',
date: "2021-01-21",
location: 'Mumbai'
}
]
const arr2 = [
{
rollNo: 1,
marks: 100,
name: 'Rohan',
date: "2021-01-19",
},
{
rollNo: 2,
marks: 90,
surname: 'Kolhi',
date: "2021-01-19",
},
{
rollNo: 3,
marks: 70,
date: "2021-01-21",
ExamCenter: {
place: 'Mumbai'
}
}
]
const newArray = [];
arr2.forEach((item) => {
const array1Item = arr1.find(({ date }) => date === item.date);
if (array1Item) {
newArray.push({
...item,
...array1Item,
})
}
})
console.log(newArray);
This may help you
const arr3 = arr1.map((value, index) => {
return Object.assign(value, arr2[index])
})

How to filter array of objects in react native?

I want to filter this data array into state and city array. How can I achieve this using lodash or any other better way rather than for loop and maintaining extra arrays.
data: [
{ id: 1, name: Mike, city: philps, state: New York},
{ id: 2, name: Steve, city: Square, state: Chicago},
{ id: 3, name: Jhon, city: market, state: New York},
{ id: 4, name: philps, city: booket, state: Texas},
{ id: 5, name: smith, city: brookfield, state: Florida},
{ id: 6, name: Broom, city: old street, state: Florida},
]
which user click state, list of state appears.
{state: New York, count: 2},
{state: Texas, count: 1},
{state: Florida, count: 2},
{state: Chicago, count: 1},
When user click particular state, list of cities of that state appears. For ex. when user clicks New York state,
{id:1, name: Mike, city: philps}
{id:3, name: Jhon, city: market}
You can do this using native javascript by applying filter method which accepts as parameter a callback provided function.
let data = [ { id: 1, name: 'Mike', city: 'philps', state:'New York'}, { id: 2, name: 'Steve', city: 'Square', state: 'Chicago'}, { id: 3, name: 'Jhon', city: 'market', state: 'New York'}, { id: 4, name: 'philps', city: 'booket', state: 'Texas'}, { id: 5, name: 'smith', city: 'brookfield', state: 'Florida'}, { id: 6, name: 'Broom', city: 'old street', state: 'Florida'}, ]
data = data.filter(function(item){
return item.state == 'New York';
}).map(function({id, name, city}){
return {id, name, city};
});
console.log(data);
Another approach is to use arrow functions.
let data = [ { id: 1, name: 'Mike', city: 'philps', state:'New York'}, { id: 2, name: 'Steve', city: 'Square', state: 'Chicago'}, { id: 3, name: 'Jhon', city: 'market', state: 'New York'}, { id: 4, name: 'philps', city: 'booket', state: 'Texas'}, { id: 5, name: 'smith', city: 'brookfield', state: 'Florida'}, { id: 6, name: 'Broom', city: 'old street', state: 'Florida'}, ]
data = data.filter((item) => item.state == 'New York').map(({id, name, city}) => ({id, name, city}));
console.log(data);
With lodash, you could use _.filter with an object as _.matches iteratee shorthand for filtering the object with a given key/value pair and
use _.countBy with _.map for getting a count of states.
var data = [{ id: 1, name: 'Mike', city: 'philps', state: 'New York' }, { id: 2, name: 'Steve', city: 'Square', state: 'Chicago' }, { id: 3, name: 'Jhon', city: 'market', state: 'New York' }, { id: 4, name: 'philps', city: 'booket', state: 'Texas' }, { id: 5, name: 'smith', city: 'brookfield', state: 'Florida' }, { id: 6, name: 'Broom', city: 'old street', state: 'Florida' }];
console.log(_.filter(data, { state: 'New York' }));
console.log(_
.chain(data)
.countBy('state')
.map((count, state) => ({ state, count }))
.value()
);
.as-console-wrapper { max-height: 100% !important; top: 0; }
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.15.0/lodash.min.js"></script>
Simply Follow filter function
For Example
return data.filter(data => data.state == "New York" && count === 2);
This is fairly simple using Array.prototype.filter, Array.prototype.map, Array.prototype.reduce and destructuring:
//filter by particular state
const state = /*the given state*/;
const filtered = data
.filter(e => e.state == state)//filter to only keep elements from the same state
.map(e => {
const {id, name, city} = e;
return {id, name, city};
});//only keep the desired data ie id, name and city
//get states array
const states = data
.reduce((acc, elem) => {
const state_names = acc.map(e => e.state);//get all registered names
if(state_names.includes(elem.state)){//if it is already there
const index = acc.find(e => e.state==elem.state);
acc[index] = {state: acc[index].state, count: acc[index].count+1};//increment it's count
return acc;
}else//otherwise
return [...acc, {state: elem.state, count: 1}];//create it
}, []);
cf this jsfiddle to see it in action.

Categories

Resources