我有一个由三个不同对象组成的非规范化数组-country, school, student
const input=
[
{
countryID: 12,
country: "US",
schoolID: 122,
schoolZone: "Highlands",
studentID: 142,
studentName: "Mary"
},
{
countryID: 12,
country: "US",
schoolID: 122,
schoolZone: "Highlands",
studentID: 145,
studentName: "John"
},
{
countryID: 14,
country: "UK",
schoolID: 222,
schoolZone: "Leeds",
studentID: 223,
studentName: "Peter"
}
];
我想像这样规范他们
const result=
[
{
countryID: 12,
country: "US",
schools: [
{
schoolID: 122,
schoolZone: "Highlands",
students: [
{
studentID: 142,
studentName: "Mary"
},
{
studentID: 145,
studentName: "John"
}
]
}
]
},
{
countryID: 14,
country: "UK",
schools: [
{
schoolID: 222,
schoolZone: "Leeds",
students: [
{
studentID: 223,
studentName: "Peter"
}
]
}
]
}
];
我了解lodash
和ramda
可用于实现嵌套归一化
但是我对这两个库都是新手。
您能帮我实施吗?还想知道如果考虑到schools
和students
答案 0 :(得分:1)
不使用lodash或ramda的方法可能是这样。希望这会有所帮助。
const input= [{
countryID: 12,
country: "US",
schoolID: 122,
schoolZone: "Highlands",
studentID: 142,
studentName: "Mary"
}, {
countryID: 12,
country: "US",
schoolID: 122,
schoolZone: "Highlands",
studentID: 145,
studentName: "John"
}, {
countryID: 14,
country: "UK",
schoolID: 222,
schoolZone: "Leeds",
studentID: 223,
studentName: "Peter"
}];
const normalize = (data) =>
data.reduce((acc, { studentID, studentName, schoolID, schoolZone, countryID, country }) => {
const studentToAdd = { studentID, studentName };
const schoolToAdd = { schoolID, schoolZone, students: [studentToAdd] };
const countryToAdd = { countryID, country, schools: [schoolToAdd] };
const existingCountry = acc.find(item => item.countryID === countryID);
if (existingCountry) {
const existingSchool = existingCountry.schools.find(item => item.schoolID === schoolID);
if (existingSchool) {
const existingStudent = existingSchool.students.find(item => item.studentID === studentID);
if (!existingStudent) existingSchool.students.push(studentToAdd);
}
else existingCountry.schools.push(schoolToAdd);
}
else acc.push(countryToAdd);
return acc;
}, []);
console.log(normalize(input));
答案 1 :(得分:1)
使用lodash,您可以通过以下简洁的方法解决此问题:
const data = [{ countryID: 12, country: "US", schoolID: 122, schoolZone: "Highlands", studentID: 142, studentName: "Mary" }, { countryID: 12, country: "US", schoolID: 122, schoolZone: "Highlands", studentID: 145, studentName: "John" }, { countryID: 14, country: "UK", schoolID: 222, schoolZone: "Leeds", studentID: 223, studentName: "Peter" } ];
const grp = (arr, key, field, group, o=0) => _(arr)
.groupBy(key)
.mapValues(x => ({
[key]: _.head(x)[key],
[field]: _.head(x)[field],
[group]: o
? _.map(x, s => _.pick(s, ['studentID', 'studentName']))
: grp(x, 'schoolID', 'schoolZone', 'students', 1)
}))
.values()
.value()
console.log(grp(data, 'countryID', 'country', 'schools'))
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.10/lodash.min.js"></script>
该想法是使用递归方法,其中两次调用同一分组函数。在其中,我们将_.groupBy
进行_.mapValues
现在,使用紧凑的 ES6 代码的想法完全相同:
const data = [{ countryID: 12, country: "US", schoolID: 122, schoolZone: "Highlands", studentID: 142, studentName: "Mary" }, { countryID: 12, country: "US", schoolID: 122, schoolZone: "Highlands", studentID: 145, studentName: "John" }, { countryID: 14, country: "UK", schoolID: 222, schoolZone: "Leeds", studentID: 223, studentName: "Peter" } ];
const groupBy = (arr, k) => arr.reduce((r,c) => (r[c[k]] = [...r[c[k]] || [], c], r), {})
const pick = (obj, fields) => fields.reduce((r,f) => (r[f] = obj[f], r), {})
const grp = (arr, k, f, b, o=0) =>
Object.values(Object.values(groupBy(arr, k)).map(x => ({
[k]: x[0][k],
[f]: x[0][f],
[b]: o
? x.map(s => pick(s, ['studentID', 'studentName']))
: grp(x, 'schoolID', 'schoolZone', 'students', 1)
})))
console.log(grp(data, 'countryID', 'country', 'schools'))
答案 2 :(得分:0)
首先将每个对象重塑为最终的数据结构:
reshape({
countryID: 12,
country: "US",
schoolID: 122,
schoolZone: "Highlands",
studentID: 142,
studentName: "Mary" });
//=> {
//=> country: "US",
//=> countryID: 12,
//=> schools: [
//=> {
//=> schoolID: 122,
//=> schoolZone: "Highlands",
//=> students: [
//=> {
//=> studentID: 142,
//=> studentName: "Mary"
//=> }
//=> ]
//=> }
//=> ]
//=> }
那么这仅仅是一个问题,首先要按国家分组,然后按学校分组,并使用地图和归约功能合并对象。
const {pick, map, groupBy, values, lensProp, over, reduce, mergeWithKey, pipe, prop, applySpec, converge, set, of} = R;
const input = [
{ countryID: 12,
country: "US",
schoolID: 122,
schoolZone: "Highlands",
studentID: 142,
studentName: "Mary" },
{ countryID: 12,
country: "US",
schoolID: 122,
schoolZone: "Highlands",
studentID: 145,
studentName: "John" },
{ countryID: 14,
country: "UK",
schoolID: 222,
schoolZone: "Leeds",
studentID: 223,
studentName: "Peter" }];
const reshape = applySpec({
countryID: prop('countryID'),
country: prop('country'),
schools: converge(
pipe(set(lensProp('students')), of), [
pipe(pick(['studentID', 'studentName']), of),
pick(['schoolID', 'schoolZone'])])
});
const mergeArrays = key => mergeWithKey((k, a, b) => k === key ? [a[0], b[0]] : a);
const groupStudents = pipe(
groupBy(prop('schoolID')),
values,
map(reduce(mergeArrays('students'), {})));
const process = pipe(
map(reshape),
groupBy(prop('countryID')),
map(reduce(mergeArrays('schools'), {})),
map(over(lensProp('schools'), groupStudents)),
values);
console.log(process(input));
<script src="https://cdnjs.cloudflare.com/ajax/libs/ramda/0.25.0/ramda.min.js"></script>