计算一个值在对象数组中出现的次数
Count how many times a value occurs in a array of objects
假设我有:
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 = {
1: { a: 4, b: 3 },
2: { a: 2, b: 0, c: 3, d: 1 },
3: { a: 3, b: 2, c: 2 }
}
result
是一个对象,其键是map1
id
,值是包含累加和的对象。
例如:
result[2] = { a: 2, b: 0, c: 3, d: 1 }
因为在 map2.map1
中循环每个对象并使用键 2
查看值(2 因为我们正在寻找结果 [2])有 2 次 a
、0 次 b
、3 次 c
和 1 次 d
。
我想我必须使用 reduce
但是如何呢?对我来说似乎太复杂了..
这是我的出发点:
const results = map2.reduce((accumulator, current) => {
// ??
return accumulator
}, [])
您可以计算所有 key/value 对 map2
并从 map1
生成想要的结果。
对于每个给定的数组,此方法只需要 一个循环。
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; }
您可以结合使用 reduce
、map
和 filter
方法。
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)
您可以首先创建一个查找 table 以通过循环遍历 map2
来创建一个由 1-a
、2-b
等键控的对象来快速检索。其中每个值存储每个键的 count/occurrences。然后,一旦你有了查找 table,你就可以在你的 map1
上使用 .map()
and Object.fromEntries()
来使用之前构建的查找 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);
我是这样解决的:
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
}, {})
假设我有:
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 = {
1: { a: 4, b: 3 },
2: { a: 2, b: 0, c: 3, d: 1 },
3: { a: 3, b: 2, c: 2 }
}
result
是一个对象,其键是map1
id
,值是包含累加和的对象。
例如:
result[2] = { a: 2, b: 0, c: 3, d: 1 }
因为在 map2.map1
中循环每个对象并使用键 2
查看值(2 因为我们正在寻找结果 [2])有 2 次 a
、0 次 b
、3 次 c
和 1 次 d
。
我想我必须使用 reduce
但是如何呢?对我来说似乎太复杂了..
这是我的出发点:
const results = map2.reduce((accumulator, current) => {
// ??
return accumulator
}, [])
您可以计算所有 key/value 对 map2
并从 map1
生成想要的结果。
对于每个给定的数组,此方法只需要 一个循环。
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; }
您可以结合使用 reduce
、map
和 filter
方法。
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)
您可以首先创建一个查找 table 以通过循环遍历 map2
来创建一个由 1-a
、2-b
等键控的对象来快速检索。其中每个值存储每个键的 count/occurrences。然后,一旦你有了查找 table,你就可以在你的 map1
上使用 .map()
and Object.fromEntries()
来使用之前构建的查找 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);
我是这样解决的:
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
}, {})