Merge objects in a loop - javascript

I have this array of arrays of objects :
[
[
{a: 'FER', b: 'MEN', c: 'TUM'},
{a: 'RIS ', b: 'US', c: 'SOU'},
{a: 'CON', b: 'SEC', c: 'TETUR'}
],
[
{d: 'LIGU'},
{d: 'GU'},
{d: 'LA'}
],
[
{e: 'UL', f: 'LAM'},
{e: 'COR', f: 'PER'},
{e: 'EGE', f: 'STAS'}
]
]
What I want to obtain in the more generic manner is this (in reality, I have one array of 21 arrays with 205 objects in each):
[
{a: 'FER', b: 'MEN', c: 'TUM', d: 'LIGU', e: 'UL', f: 'LAM'},
{a: 'RIS ', b: 'US', c: 'SOU', d: 'GU', e: 'COR', f: 'PER'},
{a: 'CON', b: 'SEC', c: 'TETUR', d: 'LA', e: 'EGE', f: 'STAS'}
]
I tried so many things (object assign, reduce, etc.) but my head is a mess right now and I'm stuck on how I can merge objects in a loop.
Any help so much appreciated!

You could reduce with a mapping of objects.
const
data = [[{ a: 'FER', b: 'MEN', c: 'TUM' }, { a: 'RIS ', b: 'US', c: 'SOU' }, { a: 'CON', b: 'SEC', c: 'TETUR' }], [{ d: 'LIGU' }, { d: 'GU' }, { d: 'LA' }], [{ e: 'UL', f: 'LAM' }, { e: 'COR', f: 'PER' }, { e: 'EGE', f: 'STAS' }]],
result = data.reduce((a, b) => a.map((o, i) => ({ ...o, ...b[i] })));
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }

Using Array#reduce and Array#forEach:
const data = [
[
{ a: 'FER', b: 'MEN', c: 'TUM' },
{ a: 'RIS ', b: 'US', c: 'SOU' },
{ a: 'CON', b: 'SEC', c: 'TETUR' }
],
[
{ d: 'LIGU' },
{ d: 'GU' },
{ d: 'LA' }
],
[
{ e: 'UL', f: 'LAM' },
{ e: 'COR', f: 'PER' },
{ e: 'EGE', f: 'STAS' }
]
];
const res = data.reduce((acc, arr) => {
arr.forEach((obj, i) => {
acc[i] = { ...(acc[i] || {}), ...obj };
});
return acc;
}, []);
console.log(res);

var counter = 0,
finalarr = [],
tmpobj = {};
while (counter < arr[0].length) {
tmpobj = {}
arr.forEach((subarr, index) => {
tmpobj = {
...tmpobj,
...subarr[counter]
}
})
finalarr.push(tmpobj)
counter++;
}
console.log('Final array:', finalarr)

Related

JS: Group by 2 keys

I have like to group an array of objects.
var _ = require('lodash')
const objects = [
{ a: 'test1', b: 'sample', c: 'ten' },
{ a: 'test2', b: 'sample', c: 'ten' },
{ a: 'test3', b: 'sampleone', c: 'ten' },
{ a: 'test4', b: 'sample', c: 'tentwo' },
]
//using lodash, groupBy b and c and concat 'a' values
const grouped = _(objects)
.groupBy('b', 'c')
.map((value, key) => ({
b: key,
c: value[0].c,
a: _.map(value, 'a').join('|'),
}))
.value()
console.log(grouped)
The output from above is:
[
{ b: 'sample', c: 'ten', a: 'test1|test2|test4' },
{ b: 'sampleone', c: 'ten', a: 'test3' }
]
But I have like the output to be below, only group by b is 'sample' and c is 'ten'
[
{ b: 'sample', c: 'ten', a: 'test1|test2' },
{ b: 'sampleone', c: 'ten', a: 'test3' },
{ b: 'sample', c: 'tentwo', a: 'test4' }
]
Any help would be greatly appreciated.
To group by multiple keys you will to need do something like
.groupBy(({b,c}) => `${b}|${c}`)
i.e joining the individual keys and creating a new composite key (also will have create it in such a way that it becomes unique)
now the grouped object will look like this before the map call
{
sampleone|ten: [{
a: "test3",
b: "sampleone",
c: "ten"
}],
sample|ten: [{
a: "test1",
b: "sample",
c: "ten"
}, {
a: "test2",
b: "sample",
c: "ten"
}],
sample|tentwo: [{
a: "test4",
b: "sample",
c: "tentwo"
}]
}
const objects = [
{ a: 'test1', b: 'sample', c: 'ten' },
{ a: 'test2', b: 'sample', c: 'ten' },
{ a: 'test3', b: 'sampleone', c: 'ten' },
{ a: 'test4', b: 'sample', c: 'tentwo' },
]
const grouped = _(objects)
.groupBy(({b,c}) => `${b}|${c}`)
.map((value, key) => ({
b: value[0].b,
c: value[0].c,
a: _.map(value, 'a').join('|'),
}))
.value()
console.log(grouped)
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.21/lodash.min.js"></script>

Find elements in array of objects that have same properties and create a new array of objects

I have an array of objects like this:
arr = [
{ a: "dog", b: 8, c: "male", d: "big", e: 100 },
{ a: "dog1", b: 5, c: "female", d: "big", e: 200},
{ a: "dog2", b: 18, c: "female", d: "big", e: 350},
{ a: "dog2", b: 18, c: "female", d: "big", e: 350},
{ a: "dog", b: 3, c: "male", d: "big", e: 100 },
{ a: "dog", b: 8, c: "male", d: "big", e: 100 },
];
I want to create a new array containing only the property a and the sum of e of those objects that have the same values for b, c and d, so that I'll have and array like this:
arr2 = [
{ a: "dog", e: 300 },
{ a: "dog2", e: 700},
];
I've already tried to use a map function inside a map function looking for the elements that have the same properties b, c and d, then pushing the result in the arr2, but it pushes every time all the objects of my initial arr.
You could use Array.reduce to create a map of the array elements, using b,c and d combined as the key.
Once we have this map, we can use Object.values() to get an array as the desired result.
arr = [
{ a: 'dog', b: 8, c: 'male', d: 'big', e: 100 },
{ a: 'dog1', b: 5, c: 'female', d: 'big', e: 200},
{ a: 'dog2', b: 18, c: 'female', d: 'big', e: 350},
{ a: 'dog2', b: 18, c: 'female', d: 'big', e: 350},
{ a: 'dog', b: 3, c: 'male', d: 'big', e: 100 },
{ a: 'dog', b: 8, c: 'male', d: 'big', e: 100 },
];
const result = Object.values(arr.reduce((acc, cur) => {
// Create a key from b,c,d..
const key = cur.b + cur.c + cur.d
acc[key] = acc[key] || { a: cur.a, e: 0 };
acc[key].e += cur.e;
return acc;
}, {}))
console.log('Result:', result);
Universal solution for arbitrary array and keys to summarize
If you're looking for vanilla JS solution (no lodash), you may come up with something, adjustable to arbitrary group key property and property to summarize with Array.prototype.reduce():
build the Map, having desired property as a key;
increment Map items, based on the matching key
get Map.prototype.values() of that Map into array
const src = [
{ a: "dog", b: 8, c: "male", d: "big", e: 100 },
{ a: "dog1", b: 5, c: "female", d: "big", e: 200},
{ a: "dog2", b: 18, c: "female", d: "big", e: 350},
{ a: "dog2", b: 18, c: "female", d: "big", e: 350},
{ a: "dog", b: 3, c: "male", d: "big", e: 100 },
{ a: "dog", b: 8, c: "male", d: "big", e: 100 },
]
const summarizeValueByKey = (arr, key, val) =>
[...arr
.reduce((acc,{[key]: keyProp, [val]: valProp}) => {
const group = acc.get(keyProp)
group
? group[val] += valProp
: acc.set(keyProp, {[key]: keyProp, [val]: valProp})
return acc
}, new Map)
.values()]
console.log(summarizeValueByKey(src, 'a', 'e'))

How to loop object have many array object like that

I have object 1 like that
const object1 = {
Sheet1: [
{ A: '', B: '', C: '', D: '', E: '' },
{
A: 'Cash Report - Processed',
B: 'Store: 54101 Date: 1/30/2020',
D: '',
E: ''
},
{ A: '', B: '', C: '', D: 'Adj: 00', E: 'Adj: 01' },
],
Sheet2: [ { D: 'a' }, { G: 's' }, { G: 'b' } ]
};
I want delete blank data but I have issue when I loop object 1, I can't get keym my code
Object.keys(object1).forEach(function(key) {
console.log(key, object1[key]);
});
I want data will like that
{
Sheet1: [
{
A: 'Cash Report - Processed',
B: 'Store: 54101 Date: 1/30/2020',
},
{ D: 'Adj: 00', E: 'Adj: 01' },
],
Sheet2: [ { D: 'a' }, { G: 's' }, { G: 'b' } ]
};
You can accomplish this using Object.entries and Array.reduce.
const input = {
Sheet1: [
{ A: '', B: '', C: '', D: '', E: '' },
{
A: 'Cash Report - Processed',
B: 'Store: 54101 Date: 1/30/2020',
D: '',
E: ''
},
{ A: '', B: '', C: '', D: 'Adj: 00', E: 'Adj: 01' },
],
Sheet2: [ { D: 'a' }, { G: 's' }, { G: 'b' } ]
};
const output = Object.entries(input).reduce((acc, cur) => {
acc[cur[0]] = cur[1].reduce((curAcc, curVal) => {
const notNull = Object.entries(curVal).filter(([ key, val ]) => val);
if (notNull.length > 0) {
curAcc.push(Object.fromEntries(notNull));
}
return curAcc;
}, []);
return acc;
}, {});
console.log(output);
Use this:
for(const key in object1){
const element = object1[key];
object1[key] = element.map(x => {
for(const prop in x){
if(!x[prop]){
delete x[prop];
}
}
return Object.keys(x).length ? x : null
}).filter(x => !!x);
};
Use Object.entries to transform object to array of key-value pairs, manipulate that pairs, remove pairs with empty value, then transform back to object using Object.fromEntries
const object1 = {
Sheet1: [
{ A: "", B: "", C: "", D: "", E: "" },
{
A: "Cash Report - Processed",
B: "Store: 54101 Date: 1/30/2020",
D: "",
E: "",
},
{ A: "", B: "", C: "", D: "Adj: 00", E: "Adj: 01" },
],
Sheet2: [{ D: "a" }, { G: "s" }, { G: "b" }],
}
const notEmptyObject = (obj) => Object.keys(obj).length > 0
const removeEmptyValues = (obj) =>
Object.fromEntries(Object.entries(obj).filter(([_, value]) => Boolean(value)))
const res = Object.fromEntries(
Object.entries(object1).map(([sheet, data]) => [
sheet,
data
.map(removeEmptyValues)
.filter(notEmptyObject),
])
)
console.log(res)

How to reshaping Data in Javascript from array to object without losing some of the data

I am trying to add the key to each so that I can be able to easy make a multi scatter plot in d3. . I am not sure how to do it.
EDIT: TO CLARIFY what I meant.
Data:
var dataOriginal = {
Apples: [{"A":4,"B":null,"C":null,"D":2}, {"A":5,"B":null,"C":3,"D":2}],
Oranges: [{"A":3,"B":1,"C":4,"D":4.3}],
Jackfruit: [{"A":5,"B":4,"C":4,"D":3}],
Avocado: [{"A":null,"B":33,"C":2,"D":9.66}],
Pomegranate: [{"A":5,"B":3.5,"C":null,"D":6}]
}
Function:
const data = Object.keys(dataOriginal).map((key) => {
const temp = {...dataOriginal[key]};
temp.key = key;
return temp;
});
Results:
0:
0: {A: 4, B: null, C: null, D: 2}
1: {A: 5, B: null, C: 3, D: 2}
key: "Apples"
__proto__: Object
1:
0: {A: 3, B: 1, C: 4, D: 4.3}
key: "Oranges"
__proto__: Object
2:
0: {A: 5, B: 4, C: 4, D: 3}
key: "Jackfruit"
__proto__: Object
3:
0: {A: null, B: 33, C: 2, D: 9.66}
key: "Avocado"
__proto__: Object
4: {0: {…}, key: "Pomegranate"}
Desired results
: {A: 4, B: null, C: null, D: 2, key: "Apples"}
1: {A: 3, B: 1, C: 4, D: 4.3, key: "Oranges"}
2: {A: 5, B: 4, C: 4, D: 3, key: "Jackfruit"}
3: {A: null, B: 33, C: 2, D: 9.66, key: "Avocado"}
4: {A: 5, B: 3.5, C: null, D: 6, key: "Pomegranate"}
5: {A:5,B:null,C:3,D:2, key: "Apples"}
You need to reduce the object to get a single object with added values.
const
addByKey = array => array.reduce((a, b) => {
Object.entries(b).forEach(([k, v]) => a[k] = (a[k] || 0) + v);
return a;
}, {}),
dataOriginal = { Apples: [{ A: 4, B: null, C: null, D: 2 }, { A: 5, B: null, C: 3, D: 2 }], Oranges: [{ A: 3, B: 1, C: 4, D: 4.3 }], Jackfruit: [{ A: 5, B: 4, C: 4, D: 3 }], Avocado: [{ A: null, B: 33, C: 2, D: 9.66 }], Pomegranate: [{ A: 5, B: 3.5, C: null, D: 6 }] }
data = Object.keys(dataOriginal).map((key) => ({ ...addByKey(dataOriginal[key]), key }));
console.log(data);
.as-console-wrapper { max-height: 100% !important; top: 0; }
For getting single object with same keys, you could map the objects, add the key and get a flat array.
const
dataOriginal = { Apples: [{ A: 4, B: null, C: null, D: 2 }, { A: 5, B: null, C: 3, D: 2 }], Oranges: [{ A: 3, B: 1, C: 4, D: 4.3 }], Jackfruit: [{ A: 5, B: 4, C: 4, D: 3 }], Avocado: [{ A: null, B: 33, C: 2, D: 9.66 }], Pomegranate: [{ A: 5, B: 3.5, C: null, D: 6 }] }
data = Object
.keys(dataOriginal)
.flatMap(key => dataOriginal[key].map(o => ({ ...o, key })));
console.log(data);
.as-console-wrapper { max-height: 100% !important; top: 0; }
The reason why {"A":5,"B":null,"C":3,"D":2} is missed is because, index 0 is hardcoded in the code.
const temp = {...dataOriginal[key][0]};
Alternate solution:
var dataOriginal = {
Apples: [{"A":4,"B":null,"C":null,"D":2}, {"A":5,"B":null,"C":3,"D":2}],
Oranges: [{"A":3,"B":1,"C":4,"D":4.3}],
Jackfruit: [{"A":5,"B":4,"C":4,"D":3}],
Avocado: [{"A":null,"B":33,"C":2,"D":9.66}],
Pomegranate: [{"A":5,"B":3.5,"C":null,"D":6}]
}
const myData =[]
Object.keys(dataOriginal).map((key) => {
for (let i = 0; i < dataOriginal[key].length; i++) {
myData.push({...dataOriginal[key][i], key})
}
})
console.log(myData)

Elegant array transformation in Javascript

What's an elegent way - purely functional, ideally - to transform (reduce?) this array:
var in = [
{ a: 1, b: 'x', c: 'foo' },
{ a: 1, b: 'y', c: 'goo' },
{ a: 2, b: 'x', c: 'hoo' },
{ a: 2, b: 'y', c: 'joo' }
]
Into this:
var out = [
{ a: 1, x: 'foo', y: 'goo' },
{ a: 2, x: 'hoo', y: 'joo' }
]
The logic is that all elements should be joined based on their a property, and all b and c properties denote key/value pairs respectively that should be merged into the single object based on their shared a value.
You can use a hash object, and reduce to wrap the hashing like this:
const arr = [
{ a: 1, b: 'x', c: 'foo' },
{ a: 1, b: 'y', c: 'goo' },
{ a: 2, b: 'x', c: 'hoo' },
{ a: 2, b: 'y', c: 'joo' }
];
let result = Object.values( // the result is the values of the hash object
arr.reduce((hash, o) => { // hash is a hash object that make it easier to group the result
hash[o.a] = hash[o.a] || {a: o.a}; // if there is no object in the hash that have the value of the key a equal to o.a, then create a new one
hash[o.a][o.b] = o.c; // set the value of the key stored in o.b to o.c
return hash;
}, {})
);
console.log(result);
You could use a closure with a Map
var input = [{ a: 1, b: 'x', c: 'foo' }, { a: 1, b: 'y', c: 'goo' }, { a: 2, b: 'x', c: 'hoo' }, { a: 2, b: 'y', c: 'joo' }],
output = input.reduce((map => (r, o) => (!map.has(o.a) && map.set(o.a, r[r.push({ a: o.a }) - 1]), map.get(o.a)[o.b] = o.c, r))(new Map), []);
console.log(output);
.as-console-wrapper { max-height: 100% !important; top: 0; }
You can use forEach and Object.assign to group by a and then map to return object values.
var data = [
{ a: 1, b: 'x', c: 'foo' },
{ a: 1, b: 'y', c: 'goo' },
{ a: 2, b: 'x', c: 'hoo' },
{ a: 2, b: 'y', c: 'joo' }
]
var r = {}
data.forEach(e => r[e.a] = Object.assign((r[e.a] || {}), {a: e.a, [e.b]: e.c}))
r = Object.keys(r).map(e => r[e])
console.log(r)
I like provided answers, but here is my attempt. I believe it's more readable, but it uses Object.assign and Object.values
const input = [
{ a: 1, b: 'x', c: 'foo' },
{ a: 1, b: 'y', c: 'goo' },
{ a: 2, b: 'x', c: 'hoo' },
{ a: 2, b: 'y', c: 'joo' }
]
const map = input.reduce((acc, obj) => {
const [a, key, value] = Object.values(obj)
const newObj = {a, [key]: value}
if (acc[a]) {
Object.assign(acc[a], newObj)
} else {
acc[a] = newObj
}
return acc
}, {})
console.log(Object.values(map))
Not sure if approach is elegant or functional, though returns expected result using for..of loops, Array.prototype.some() and Object.assign()
function props(array, key, prop1, prop2) {
let arr = [];
for (let obj of array) {
let o = {};
for (let {[key]:_key, [prop1]:_prop1, [prop2]:_prop2} of [obj]) {
o[_prop1] = _prop2;
o[key] = _key;
}
if (!arr.some(p => p[key] === o[key])) arr.push(o);
for (let prop of arr) {
if (prop[key] == o[key]) {
prop = Object.assign(prop, o)
}
}
}
return arr
}
var _in = [
{ a: 1, b: 'x', c: 'foo' },
{ a: 1, b: 'y', c: 'goo' },
{ a: 2, b: 'x', c: 'hoo' },
{ a: 2, b: 'y', c: 'joo' }
];
console.log(props(_in, "a", "b", "c"));

Categories

Resources