JavaScript native groupBy reduce - javascript

I am using JavaScript native reduce, however I want to slightly change in the grouping to get my desired result.
I have an array as follows:
const people = [
{name: "John", age: 23, city: "Seattle", state: "WA"},
{name: "Mark", age: 25, city: "Houston", state: "TX"},
{name: "Luke", age: 26, city: "Seattle", state: "WA"},
{name: "Paul", age: 28, city: "Portland", state: "OR"},
{name: "Matt", age: 21, city: "Oakland", state: "CA"},
{name: "Sam", age: 24, city: "Oakland", state: "CA"}
]
I want to group it and change it to this:
const arranged = [
{
city: "Seattle",
state: "WA",
persons: [
{ name: "John", age: 23 },
{name: "Luke", age: 26}
]
},
{
city: "Houston",
state: "TX",
persons: [
{name: "Mark", age: 25}
]
},
{
city: "Portland",
state: "OR",
persons : [
{name: "Paul", age: 28}
]
},
{
city: "Oakland",
state: "CA",
persons: [
{name: "Matt", age: 21},
{name: "Sam", age: 24}
]
}
]

You could use a Map and a stringified object as key for grouping.
Later render the wanted array with objects of the keys and the grouped persons.
var people = [{ name: "John", age: 23, city: "Seattle", state: "WA" }, { name: "Mark", age: 25, city: "Houston", state: "TX" }, { name: "Luke", age: 26, city: "Seattle", state: "WA" }, { name: "Paul", age: 28, city: "Portland", state: "OR" }, { name: "Matt", age: 21, city: "Oakland", state: "CA" }, { name: "Sam", age: 24, city: "Oakland", state: "CA" }],
arranged = Array.from(
people.reduce((m, o) => {
var key = JSON.stringify(Object.assign(...['city', 'state'].map(k => ({ [k]: o[k] }))));
return m.set(key, (m.get(key) || []).concat({ name: o.name, age: o.age }));
}, new Map),
([key, persons]) => Object.assign(JSON.parse(key), { persons })
);
console.log(arranged);
.as-console-wrapper { max-height: 100% !important; top: 0; }

Try this. I use Array.prototype.forEach and Array.prototype.push
const people = [
{name: "John", age: 23, city: "Seattle", state: "WA"},
{name: "Mark", age: 25, city: "Houston", state: "TX"},
{name: "Luke", age: 26, city: "Seattle", state: "WA"},
{name: "Paul", age: 28, city: "Portland", state: "OR"},
{name: "Matt", age: 21, city: "Oakland", state: "CA"},
{name: "Sam", age: 24, city: "Oakland", state: "CA"}
];
var arranged=[];
people.forEach(function(e){
var exist=false;
arranged.forEach(function(e1){
if(e1.state===e.state){
exist=true;
e1.persons.push({name:e.name,age:e.age});
}
});
if(!exist){
arranged.push({state:e.state,city:e.city,persons:[{name:e.name,age:e.age}]});
}
});
console.log(arranged);

This is not a trivial problem. You first have to define what constitutes a grouping, and you also have to define how like terms will be combined. You problem is exacerbated by the need to group by a non-primitive value: city and state. Ie, we can't just group based on city alone; more than half the states in the US have a city named Oakland. Other answers solve this by serializing the city and state in a string, but I will show you a more generic solution that works for compound data of any type.
This is tagged with functional programming, so I'll start with a module for separating our subtasks
const DeepMap =
{ has: (map, [ k, ...ks ]) =>
ks.length === 0
? map.has (k)
: map.has (k)
? DeepMap.has (map.get (k), ks)
: false
, set: (map, [ k, ...ks ], value) =>
ks.length === 0
? map.set (k, value)
: map.has (k)
? (DeepMap.set (map.get (k), ks, value), map)
: map.set (k, DeepMap.set (new Map, ks, value))
, get: (map, [ k, ...ks ]) =>
ks.length === 0
? map.get (k)
: map.has (k)
? DeepMap.get (map.get (k), ks)
: undefined
}
Now we can define our generic groupBy function
const identity = x =>
x
const { has, set, get } =
DeepMap
const groupBy = (key = identity, value = identity, xs = []) =>
xs.reduce
((m, x) =>
has (m, key (x))
? set ( m
, key (x)
, [ ...get (m, key (x)), value (x) ]
)
: set ( m
, key (x)
, [ value (x) ]
)
, new Map
)
We use groupBy by specifying a key and value functions – The key function specifies what an item is grouped by, and the value functions specifies the value to be added to the group
const people =
[ { name: "John", age: 23, city: "Seattle", state: "WA" }
, { name: "Mark", age: 25, city: "Houston", state: "TX" }
, { name: "Luke", age: 26, city: "Seattle", state: "WA" }
, { name: "Paul", age: 28, city: "Portland", state: "OR" }
, { name: "Matt", age: 21, city: "Oakland", state: "CA" }
, { name: "Sam", age: 24, city: "Oakland", state: "CA" }
]
const res =
groupBy ( k => [ k.state, k.city ]
, v => ({ name: v.name, age: v.age })
, people
)
console.log (res.get ('WA'))
// Map { 'Seattle' => [ { name: 'John', age: 23 }, { name: 'Luke', age: 26 } ] }
console.log (res.get ('WA') .get ('Seattle'))
// [ { name: 'John', age: 23 }, { name: 'Luke', age: 26 } ]
We can see how this intermediate result would be useful. It provides incredibly efficient lookup thanks to Map. Of course you'll want to iterate thru the deep map in more meaningful ways though. Let's add an entries procedure to our module
const DeepMap =
{ ...
, entries: function* (map, fields = [])
{
const loop = function* (m, path, [ f, ...fields ])
{
if (fields.length === 0)
for (const [ key, value ] of m)
yield [ { ...path, [ f ]: key }, value ]
else
for (const [ key, value ] of m)
yield* loop (value, { ...path, [ f ]: key }, fields)
}
yield* loop (map, {}, fields)
}
}
for (const [ key, value ] of DeepMap.entries (res, [ 'state', 'city' ]))
console.log (key, value)
// { state: 'WA', city: 'Seattle' } [ { name: 'John', age: 23 }, { name: 'Luke', age: 26 } ]
// { state: 'TX', city: 'Houston' } [ { name: 'Mark', age: 25 } ]
// { state: 'OR', city: 'Portland' } [ { name: 'Paul', age: 28 } ]
// { state: 'CA', city: 'Oakland' } [ { name: 'Matt', age: 21 }, { name: 'Sam', age: 24 } ]
Now that our deep map is iterable, we can easily produce your desired output using Array.from
const arranged =
Array.from ( entries (res, [ 'state', 'city' ])
, ([ key, persons ]) => ({ ...key, persons })
)
console.log (arranged)
// [
// {
// city: "Seattle",
// state: "WA",
// persons: [
// { name: "John", age: 23 },
// { name: "Luke", age: 26 }
// ]
// },
// {
// city: "Houston",
// state: "TX",
// persons: [
// { name: "Mark", age: 25 }
// ]
// },
// {
// city: "Portland",
// state: "OR",
// persons : [
// { name: "Paul", age: 28 }
// ]
// },
// {
// city: "Oakland",
// state: "CA",
// persons: [
// { name: "Matt", age: 21 },
// { name: "Sam", age: 24 }
// ]
// }
// ]
Program demonstration
const DeepMap =
{ has: (map, [ k, ...ks ]) =>
ks.length === 0
? map.has (k)
: map.has (k)
? DeepMap.has (map.get (k), ks)
: false
, set: (map, [ k, ...ks ], value) =>
ks.length === 0
? map.set (k, value)
: map.has (k)
? (DeepMap.set (map.get (k), ks, value), map)
: map.set (k, DeepMap.set (new Map, ks, value))
, get: (map, [ k, ...ks ]) =>
ks.length === 0
? map.get (k)
: map.has (k)
? DeepMap.get (map.get (k), ks)
: undefined
, entries: function* (map, fields = [])
{
const loop = function* (m, path, [ f, ...fields ])
{
if (fields.length === 0)
for (const [ key, value ] of m)
yield [ { ...path, [ f ]: key }, value ]
else
for (const [ key, value ] of m)
yield* loop (value, { ...path, [ f ]: key }, fields)
}
yield* loop (map, {}, fields)
}
}
const identity = x =>
x
const { has, set, get, entries } =
DeepMap
const groupBy = (key = identity, value = identity, xs = []) =>
xs.reduce
((m, x) =>
has (m, key (x))
? set ( m
, key (x)
, [ ...get (m, key (x)), value (x) ]
)
: set ( m
, key (x)
, [ value (x) ]
)
, new Map
)
const people =
[ { name: "John", age: 23, city: "Seattle", state: "WA" }
, { name: "Mark", age: 25, city: "Houston", state: "TX" }
, { name: "Luke", age: 26, city: "Seattle", state: "WA" }
, { name: "Paul", age: 28, city: "Portland", state: "OR" }
, { name: "Matt", age: 21, city: "Oakland", state: "CA" }
, { name: "Sam", age: 24, city: "Oakland", state: "CA" }
]
const res =
groupBy ( k => [ k.state, k.city ]
, v => ({ name: v.name, age: v.age })
, people
)
for (const [ key, value ] of entries (res, [ 'state', 'city' ]))
console.log (key, value)
// { state: 'WA', city: 'Seattle' } [ { name: 'John', age: 23 }, { name: 'Luke', age: 26 } ]
// { state: 'TX', city: 'Houston' } [ { name: 'Mark', age: 25 } ]
// { state: 'OR', city: 'Portland' } [ { name: 'Paul', age: 28 } ]
// { state: 'CA', city: 'Oakland' } [ { name: 'Matt', age: 21 }, { name: 'Sam', age: 24 } ]
const arranged =
Array.from ( entries (res, [ 'state', 'city '])
, ([ key, persons ]) => ({ ...key, persons })
)
console.log ('arranged', arranged)
// arranged [
// {
// city: "Seattle",
// state: "WA",
// persons: [
// { name: "John", age: 23 },
// { name: "Luke", age: 26 }
// ]
// },
// {
// city: "Houston",
// state: "TX",
// persons: [
// { name: "Mark", age: 25 }
// ]
// },
// {
// city: "Portland",
// state: "OR",
// persons : [
// { name: "Paul", age: 28 }
// ]
// },
// {
// city: "Oakland",
// state: "CA",
// persons: [
// { name: "Matt", age: 21 },
// { name: "Sam", age: 24 }
// ]
// }
// ]

You can use the function reduce to group and build the desired output.
const people = [ {name: "John", age: 23, city: "Seattle", state: "WA"}, {name: "Mark", age: 25, city: "Houston", state: "TX"}, {name: "Luke", age: 26, city: "Seattle", state: "WA"}, {name: "Paul", age: 28, city: "Portland", state: "OR"}, {name: "Matt", age: 21, city: "Oakland", state: "CA"}, {name: "Sam", age: 24, city: "Oakland", state: "CA"}]
const result = Object.values(people.reduce((a, {name, age, city, state}) => {
var key = [city, state].join('|');
(a[key] || (a[key] = {city, state, persons: []})).persons.push({name, age});
return a;
}, {}));
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }

I have built a generic group by reducer, you pass it the keys by which you want to group and it gives you a custom reducer function. This reducer gives you an object indexed by a (composed or simple) key containing an array of items that share this key. You can reuse it to have it grouped by the key(s) you want to.
Here are two examples.
const people = Object.freeze([{
name: "John",
age: 23,
city: "Seattle",
state: "WA"
}, {
name: "Mark",
age: 25,
city: "Houston",
state: "TX"
}, {
name: "Luke",
age: 26,
city: "Seattle",
state: "WA"
}, {
name: "Paul",
age: 28,
city: "Portland",
state: "OR"
}, {
name: "Matt",
age: 21,
city: "Oakland",
state: "CA"
}, {
name: "Sam",
age: 24,
city: "Oakland",
state: "CA"
}]);
const groupByReducer = (group) =>
(result, row) => {
const keygroup = group.map((v) => row[v]);
const key = keygroup.join(':');
if (result[key])
result[key].push(row);
else
result[key] = [row];
return result;
};
const byCityState = people.reduce(
groupByReducer(['city', 'state']), {});
const byState = people.reduce(groupByReducer(['state']), {});
console.log(byCityState);
console.log(byState);
.as-console-wrapper {
max-height: 100% !important;
top: 0;
}

Related

JS - compare 2 arrays by key, return 4 arrays: matches & unmatches from each

Interface -
interface I {
name: string;
age: number;
city: string;
address?: string;
}
Arrays -
const arr1: I[] = [
{
name: "daniel",
age: 21,
city: 'NYC'
},
{
name: "kosta",
age: 28,
city: "NYC"
},
{
name: "yoav",
age: 28,
city: "NYC"
}
];
const arr2: I[] = [{
name: "daniel",
age: 21,
city: "NYC",
address: 'E. 43'
},
{
name: "simon",
age: 24,
city: "NYC",
address: 'E. 43'
},
{
name: "david",
age: 22,
city: "NYC",
address: 'E. 43'
},
{
name: "kosta",
age: 28,
city: "NYC",
address: 'E. 43'
}
];
Getting keys for the arrays -
const arr1Map: ReadonlyMap<string, string | undefined> = new Map(
arr1.map(
({
name, age, city, address
}) => [
`${name}|${age}|${city}`,
address
]
)
);
const arr2Map: ReadonlyMap<string, string | undefined> = new Map(
arr2.map(
({
name, age, city, address
}) => [
`${name}|${age}|${city}`,
address
]
)
);
Empty arrays -
let arr1Match: I[] = []
let arr1Unmatch: I[] = []
let arr2Match: I[] = []
let arr2Unmatch: I[] = []
What I need to do now is to campare all values in arr1 to arr2, if there is a match, store the match from arr1 in arr1Match and the match from arr2 in arr2Match. If there is an Unmatch I need to store the unmatch arr1 in arr1Unmatch and the unmatch from arr2 in arr2Unmatch.
And if there is a match I need to store the address from arr2 into arr1.
The desierd output -
arr1Match: [{ name: "daniel", age: 21, city: "NYC", address: 'E. 43' }, { name: "kosta", age: 28, city: "NYC", address: 'E. 43' } ]
arr2Match: [{ name: "daniel", age: 21, city: "NYC", address: 'E. 43' }, { name: "kosta", age: 28, city: "NYC", address: 'E. 43' }]
arr1Unmatch: [{ name: "yoav", age: 28, city: "NYC" }]
arr2Unmatch: [{ name: "simon", age: 24, city: "NYC", address: 'E. 43' }, { name: "david", age: 22, city: "NYC", address: 'E. 43' }]
The answer depends on some questions about your needs: What constitutes a match? If there's different data between the matches, what should be put in the match array? Should the arrays point to the original objects, or to copies of them?
Also, it looks like there is no difference between arr1Match and arr2Match, so those can be combined into one
Either way the solution would be to iterate over one array, and search for a match in the other array for every value. Any item that doesn't match will go to the unmatch arrays
// Replace with real match logic
const isMatch = <T>(a: T, b: T) => Math.random() < 0.5;
const getMatches = <T>(arrOne: T[], arrTwo: T[]) => {
const matches: T[] = [];
const arrOneUnmatches: T[] = [];
let arrTwoUnmatches: T[];
// Copying for comfortability's sake
const arrTwoCopy = [...arrTwo];
arrOne.forEach(item => {
// Find a match in array two
const arrTwoMatchIndex = arrTwoCopy.findIndex(arrTwoItem => isMatch(item, arrTwoItem));
if (arrTwoMatchIndex) {
matches.push(item);
// Remove it from arrTwoCopy, to maintain arrTwoUnmatches
arrTwoCopy.splice(arrTwoMatchIndex, 1);
} else {
// No match = go to arrOneUnmatches
arrOneUnmatches.push(item);
}
})
// Anyone left in arrTwoCopy didn't match anyone in arrOne, so they have no match
arrTwoUnmatches = arrTwoCopy;
return { matches, arrOneUnmatches, arrTwoUnmatches }
}

Why is my condition that checks diff between two arrays of objects wrong?

What is wrong in this if condition. I am getting the wrong result. I need to get equal values in these two objects and diff between them.
const firstArr = [{ name: 'tom', age: 22, city: 'Madrid' }, { name: 'Alex', age: 23, city: 'Berlin' }, { name: 'Sara', age: 28, city: 'Paris' }, { name: 'Rash', age: 20, city: 'Dubai' } ];
const secondArr = [{ name: 'tom', age: 22, city: 'Madrid' }, { name: 'Alex', age: 27, city: 'Berlin' }, { name: 'Hary', age: 29, city: 'London' }, ];
for (let i = 0; i < firstArr.length; i++) {
for (let j = 0; j < secondArr.length; j++) {
if (firstArr[i].name == secondArr[j].name) {
console.log('eq', firstArr[i].city, secondArr[j].city)
}
if (firstArr[i].name != secondArr[j].name) {
console.log('not found in second array', firstArr[i].city)
}
if (secondArr[j].name != firstArr[i].name) {
console.log('not found in first array', secondArr[j].city)
}
}
}
Currently you compare each element of the first array with each element of the second array. You could instead use Array.prototype.some and Array.prototype.every to filter the arrays and to find the intersection resp. difference. Then you can map the objects to the city names.
const firstArr = [{ name: 'tom', age: 22, city: 'Madrid' }, { name: 'Alex', age: 23, city: 'Berlin' }, { name: 'Sara', age: 28, city: 'Paris' }, { name: 'Rash', age: 20, city: 'Dubai' } ];
const secondArr = [{ name: 'tom', age: 22, city: 'Madrid' }, { name: 'Alex', age: 27, city: 'Berlin' }, { name: 'Hary', age: 29, city: 'London' }, ];
function intersect(lhs, rhs) {
return lhs.filter(el => rhs.some(el2 => el.name === el2.name)).map(el => el.city);
}
function diff(lhs, rhs) {
return lhs.filter(el => rhs.every(el2 => el.name !== el2.name)).map(el => el.city);
}
console.log(intersect(firstArr, secondArr));
console.log(diff(firstArr, secondArr));
console.log(diff(secondArr, firstArr));
I loop the first array first and find matches in second array. If there is a match, diff is displayed. If there is no such match, then the correct text is being displayed. An array is built along the way, which is used to simplify the loop on the second array.
const firstArr = [{ name: 'tom', age: 22, city: 'Madrid' }, { name: 'Alex', age: 23, city: 'Berlin' }, { name: 'Sara', age: 28, city: 'Paris' }, { name: 'Rash', age: 20, city: 'Dubai' } ];
const secondArr = [{ name: 'tom', age: 22, city: 'Madrid' }, { name: 'Alex', age: 27, city: 'Berlin' }, { name: 'Hary', age: 29, city: 'London' }, ];
let names = [];
for (let first of firstArr) {
let matches = secondArr.filter((second) => (first.name === second.name));
if (matches.length) {
console.log('eq', first.city, matches[0].city)
} else {
console.log('not found in second array', first.city);
}
names.push(first.name);
}
for (let second of secondArr) {
if (names.indexOf(second.name) === -1) console.log('not found in first array', second.city);
}
Try this:
const firstArr = [{ name: 'tom', age: 22, city: 'Madrid' }, { name: 'Alex', age: 23, city: 'Berlin' }, { name: 'Sara', age: 28, city: 'Paris' }, { name: 'Rash', age: 20, city: 'Dubai' } ];
const secondArr = [{ name: 'tom', age: 22, city: 'Madrid' }, { name: 'Alex', age: 27, city: 'Berlin' }, { name: 'Hary', age: 29, city: 'London' }, ];
var eq = [], uniqueInFirst = [], uniqueInSecond = [];
for (let i = 0; i < firstArr.length; i++) {
var secondArrCities = Object.values(secondArr).map ((obj) => {return obj.city})
if (secondArrCities.includes(firstArr[i].city)) {
eq.push(firstArr[i].city)
} else {
uniqueInFirst.push(firstArr[i].city)
}
}
for (let i = 0; i < secondArr.length; i++) {
var firstArrCities = Object.values(firstArr).map ((obj) => {return obj.city})
if (!firstArrCities.includes(secondArr[i].city)) {
uniqueInSecond.push(secondArr[i].city)
}
}
console.log(eq)
console.log(uniqueInFirst)
console.log(uniqueInSecond)

How to filter an array of objects with only certain properties? [duplicate]

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)

return a new object with keys from array

I am trying to create a new object from the people array below, using born as a key, that contains all the people born in that year:
const newObject = {
'1971': {
male: [ [Object], [Object] ],
female: [ [Object] ]
},
'1972': {
male: [ [Object], [Object] ],
female: [ [Object] ]
}
}
Here is my code so far:
people.map(person => {
let {
born,
sex
} = person;
newPeople[born] = sex == "male" ? {
male: Array.isArray(male) && array.length ? male.push(person) : [],
female: Array.isArray(female) && female.length ? female.push(person) : []}
})
Array of people:
const people = [{
name: 'Jim',
sex: 'male',
born: '1971',
address: {
town: 'London',
},
},
{
name: 'Bob',
sex: 'male',
born: '1971',
address: {
town: 'London',
},
},....
jsfiddle setup here: https://jsfiddle.net/jw9n3bmr/
Here is a solution with reduce for what you want to do:
const people = [{
name: 'Jim',
sex: 'male',
born: '1971',
address: {
town: 'London',
},
},
{
name: 'Bob',
sex: 'male',
born: '1971',
address: {
town: 'London',
},
}
];
const result = people.reduce((acc, currVal) => {
(acc[currVal.born] || (acc[currVal.born] = { male: [], female: [] }))[currVal.sex].push(currVal);
return acc;
}, {});
console.log(result);
I hope this could helps.
const getItems = (array, key, value) => {
let items = [];
array.forEach((k, o) => { if (o[key] === value) items.push(o) });
return items;
};
console.log(getItems(people, "born", "1971"));

How to merge the property with same key in two object array?

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);

Categories

Resources