Reputation: 438
Suppose I have:
const map1 = [
{ id: 1, res: { a: `1-a`, b: `1-b` } },
{ id: 2, res: { a: `2-a`, b: `2-b`, c: `2-c`, d: `2-d` } },
{ id: 3, res: { a: `3-a`, b: `3-b`, c: `3-c` } }
]
const map2 = [
{ map1: { 1: 'a', 2: 'c', 3: 'b' } },
{ map1: { 1: 'b', 2: 'c', 3: 'a' } },
{ map1: { 1: 'a', 2: 'a' } },
{ map1: { 1: 'a', 2: 'a', 3: 'b' } },
{ map1: { 2: 'd', 3: 'a' } },
{ map1: { 1: 'a', 2: 'c', 3: 'c' } },
{ map1: { 1: 'b', 2: 'd', 3: 'c' } },
{ map1: { 1: 'b', 3: 'a' } }
]
This is the result I would like to obtain:
const result = {
1: { a: 4, b: 3 },
2: { a: 2, b: 0, c: 3, d: 1 },
3: { a: 3, b: 2, c: 2 }
}
result
is an object whose keys are map1
id
s and values are objects containing the cumulative sum.
For example:
result[2] = { a: 2, b: 0, c: 3, d: 1 }
because looping each object inside map2.map1
and looking at value with key 2
(2 because we are looking for result[2]) there are 2 times a
, 0 times b
, 3 times c
and 1 time d
.
I suppose I have to use reduce
but how? It seems too complicate to me..
Here my starting point:
const results = map2.reduce((accumulator, current) => {
// ??
return accumulator
}, [])
Upvotes: 0
Views: 95
Reputation: 438
I solved in this way:
const result = map1.reduce((counterAcc, m1) => {
const { id, res } = m1
const resIds = Object.keys(res)
const res2Ids = map2.map(({ map1 }) => map1[id])
const res2IdsWithoutUndefined = res2Ids.filter(Boolean)
counterAcc[id] = resIds.reduce((accumulator, resId) => {
accumulator[resId] = 0
const counterBy = res2IdsWithoutUndefined.reduce((resAcc, ansId) => {
const answerText = { text: res[ansId] }
if (!resAcc[ansId]) {
resAcc[ansId] = 1
} else {
resAcc[ansId] += 1
}
return resAcc;
}, {})
return { ...accumulator, ...counterBy }
}, {})
return counterAcc
}, {})
Upvotes: -1
Reputation: 50854
You can first create a lookup table for quick retrieval by looping over map2
to create an object which is keyed by by 1-a
, 2-b
, etc. where each value stores the count/occurrences of each key. Then, once you have the lookup table, you can use .map()
and Object.fromEntries()
on your map1
to build your resulting object using the previously build lookup table.
const map1 = [
{ id: 1, res: { a: `1-a`, b: `1-b` } },
{ id: 2, res: { a: `2-a`, b: `2-b`, c: `2-c`, d: `2-d` } },
{ id: 3, res: { a: `3-a`, b: `3-b`, c: `3-c` } }
]
const map2 = [
{ map1: { 1: 'a', 2: 'c', 3: 'b' } },
{ map1: { 1: 'b', 2: 'c', 3: 'a' } },
{ map1: { 1: 'a', 2: 'a' } },
{ map1: { 1: 'a', 2: 'a', 3: 'b' } },
{ map1: { 2: 'd', 3: 'a' } },
{ map1: { 1: 'a', 2: 'c', 3: 'c' } },
{ map1: { 1: 'b', 2: 'd', 3: 'c' } },
{ map1: { 1: 'b', 3: 'a' } }
];
const summed = map2.reduce((acc, {map1}) => {
Object.entries(map1).forEach(([key, val]) => {
acc[`${key}-${val}`] = (acc[`${key}-${val}`] || 0) +1;
});
return acc;
}, {});
const result = Object.fromEntries(map1.map(({id, res}) => [
id,
Object.fromEntries(Object.entries(res).map(([key, val]) => [key, summed[val] || 0]))
]));
console.log(result);
Upvotes: 1
Reputation: 386680
You could count all key/value pairs of map2
and generate the wanted result from map1
.
This approach takes only one loop for every given array.
const
map1 = [{ id: 1, res: { a: `1-a`, b: `1-b` } }, { id: 2, res: { a: `2-a`, b: `2-b`, c: `2-c`, d: `2-d` } }, { id: 3, res: { a: `3-a`, b: `3-b`, c: `3-c` } }],
map2 = [{ map1: { 1: 'a', 2: 'c', 3: 'b' } }, { map1: { 1: 'b', 2: 'c', 3: 'a' } }, { map1: { 1: 'a', 2: 'a' } }, { map1: { 1: 'a', 2: 'a', 3: 'b' } }, { map1: { 2: 'd', 3: 'a' } }, { map1: { 1: 'a', 2: 'c', 3: 'c' } }, { map1: { 1: 'b', 2: 'd', 3: 'c' } }, { map1: { 1: 'b', 3: 'a' } }],
temp = map2.reduce((r, { map1 }) => {
Object.entries(map1).forEach(e => (k => r[k] = (r[k] || 0) + 1)(e.join('-')));
return r;
}, {}),
result = map1.reduce((r, { id, res }) => {
r[id] ??= {};
Object.entries(res).forEach(([k, v]) => r[id][k] = temp[v] || 0);
return r;
}, {});
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
Upvotes: 0
Reputation: 122087
You can do this as a combination of reduce
, map
and filter
methods.
const map1 = [{"id":1,"res":{"a":"1-a","b":"1-b"}},{"id":2,"res":{"a":"2-a","b":"2-b","c":"2-c","d":"2-d"}},{"id":3,"res":{"a":"3-a","b":"3-b","c":"3-c"}}]
const map2 = [{"map1":{"1":"a","2":"c","3":"b"}},{"map1":{"1":"b","2":"c","3":"a"}},{"map1":{"1":"a","2":"a"}},{"map1":{"1":"a","2":"a","3":"b"}},{"map1":{"2":"d","3":"a"}},{"map1":{"1":"a","2":"c","3":"c"}},{"map1":{"1":"b","2":"d","3":"c"}},{"map1":{"1":"b","3":"a"}}]
const result = map1.reduce((r, { id }) => {
r[id] = map2
.map(({ map1 }) => map1[id])
.filter(Boolean)
.reduce((a, e) => {
if (!a[e]) a[e] = 0;
a[e] += 1
return a
}, {})
return r
}, {})
console.log(result)
Upvotes: 1