如何根据字符串索引对对象数组进行分组和排序
How to group and sort object array based on string index
我想将我的平面数组分组并重新排列成一个对象数组,其中每个对象都在其子属性中包含其直接后代。
我的输入数据-:
const data = [
{ lineNo: '1' },
{ lineNo: '1-1' },
{ lineNo: '1-2' },
{ lineNo: '1-3' },
{ lineNo: '1-4' },
{ lineNo: '1-11' },
{ lineNo: '1-2-1' },
{ lineNo: '1-2-3' },
{ lineNo: '1-2-2' },
{ lineNo: '1-2-4' },
{ lineNo: '1-3-1' },
{ lineNo: '1-3-2' },
{ lineNo: '1-3-3' },
{ lineNo: '1-11-1' },
{ lineNo: '1-11-2' },
{ lineNo: '1-11-3' },
{ lineNo: '2' },
{ lineNo: '2-1' },
{ lineNo: '2-2' },
{ lineNo: '2-3' },
{ lineNo: '2-2-1' },
{ lineNo: '2-2-2' },
];
我想要的输出-:
const newData = [
{
lineNo: '1',
children: [{ lineNo: '1-1' }, { lineNo: '1-2' }, { lineNo: '1-3' }, { lineNo: '1-4' }, { lineNo: '1-11' }],
},
{
lineNo: '1-2',
children: [{ lineNo: '1-2-1' }, { lineNo: '1-2-2' }, { lineNo: '1-2-3' }, { lineNo: '1-2-4' }],
},
{
lineNo: '1-3',
children: [{ lineNo: '1-3-1' }, { lineNo: '1-3-2' }, { lineNo: '1-3-3' }],
},
{
lineNo: '1-11',
children: [{ lineNo: '1-11-1' }, { lineNo: '1-11-2' }, { lineNo: '1-11-3' }],
},
{
lineNo: '2',
children: [{ lineNo: '2-1' }, { lineNo: '2-2' }, { lineNo: '2-3' }],
},
{
lineNo: '2-2',
children: [{ lineNo: '2-2-1' }, { lineNo: '2-2-2' }],
},
];
注意:生成的数据必须遵循输出中提到的数字顺序。
到目前为止我做了什么-:
const data = [
{ lineNo: '1' },
{ lineNo: '1-1' },
{ lineNo: '1-2' },
{ lineNo: '1-3' },
{ lineNo: '1-4' },
{ lineNo: '1-11' },
{ lineNo: '1-11-1' },
{ lineNo: '1-11-2' },
{ lineNo: '1-11-3' },
{ lineNo: '1-2-1' },
{ lineNo: '1-2-3' },
{ lineNo: '1-2-2' },
{ lineNo: '1-2-4' },
{ lineNo: '1-2-1-1' },
{ lineNo: '1-2-1-2' },
{ lineNo: '1-2-1-3' },
{ lineNo: '1-3-1' },
{ lineNo: '1-3-2' },
{ lineNo: '1-3-3' },
];
function createTree(data: any) {
const tree: any[] = [];
data.reduce(
(r: any, o: any) => {
o.lineNo
.split('-')
.map((_: any, i: any, a: any) => a.slice(0, i + 1).join('-'))
.reduce((q: any, lineNo: any, i: any, { length }: any) => {
let temp = (q.children = q.children || []).find((p: any) => p.lineNo === lineNo);
if (!temp) {
q.children.push((temp = { lineNo }));
}
if (i + 1 === length) {
Object.assign(temp, o);
}
return temp;
}, r);
return r;
},
{ children: tree }
);
return tree;
}
const createFlat = (data: any) => {
const flat: any[] = [];
const flatData = (data: any) => {
data.forEach((item: any) => {
if (item.children) {
flat.push(item);
flatData(item.children);
}
});
};
flatData(data);
return JSON.parse(JSON.stringify(flat));
};
const getCleanData = (data: any) => {
const cleanData: any[] = [];
function delChildren(obj: any) {
if (obj.children) {
obj.children.forEach((item: any) => {
if (item.children) {
delete item.children;
}
});
}
return obj;
}
data.forEach(function (item: any) {
cleanData.push(delChildren(item));
});
return cleanData;
};
const treeData = createTree(data);
const flatData = createFlat(treeData);
const cleanData = getCleanData(flatData);
console.log(JSON.stringify(cleanData, null, 2));
我正在寻找一种简单明了的方法。
谢谢!
您可以先使用“自然”排序对数据进行排序。 JavaScript localeCompare
有一个选项。
然后创建一个由 lineNo
键控的 Map
并将具有相同 lineNo
属性 和空 children
数组的对象作为相应的值 属性.
然后再次迭代数据以填充那些 children
数组。
提取Map
值并删除那些具有空children
数组的对象,除非它们是top-level节点(边界例)。
这是一个实现:
function createTree(data) {
// Apply natural ordering
data = [...data].sort((a, b) =>
a.lineNo.localeCompare(b.lineNo, "en", { numeric: true })
);
// Create key/value pairs for all lineNo in a Map
let map = new Map(data.map(({lineNo}) => [lineNo, { lineNo, children: [] }]));
// Populate the children arrays
for (let {lineNo} of data) {
map.get(lineNo.replace(/-?\d+$/, ""))?.children?.push({lineNo});
}
// Exclude the nodes that have no children, except if they are top-level
return [...map.values()].filter(({lineNo, children}) =>
!lineNo.includes("-") || children.length
);
}
// Demo
const data = [{ lineNo: '1-1' },{ lineNo: '1-2' },{ lineNo: '1-3-2' },{ lineNo: '1-11-2' },{ lineNo: '1-3' },{ lineNo: '1-11' },{ lineNo: '1-2-3' },{ lineNo: '1-2-2' },{ lineNo: '1' },{ lineNo: '1-2-1' },{ lineNo: '1-2-4' },{ lineNo: '1-11-1' },{ lineNo: '1-3-1' },{ lineNo: '1-4' },{ lineNo: '1-3-3' },{ lineNo: '2-1' },{ lineNo: '2-2' },{ lineNo: '2-2-1' },{ lineNo: '1-11-3' },{ lineNo: '2' },{ lineNo: '2-3' },{ lineNo: '2-2-2' },];
console.log(createTree(data));
我想将我的平面数组分组并重新排列成一个对象数组,其中每个对象都在其子属性中包含其直接后代。
我的输入数据-:
const data = [
{ lineNo: '1' },
{ lineNo: '1-1' },
{ lineNo: '1-2' },
{ lineNo: '1-3' },
{ lineNo: '1-4' },
{ lineNo: '1-11' },
{ lineNo: '1-2-1' },
{ lineNo: '1-2-3' },
{ lineNo: '1-2-2' },
{ lineNo: '1-2-4' },
{ lineNo: '1-3-1' },
{ lineNo: '1-3-2' },
{ lineNo: '1-3-3' },
{ lineNo: '1-11-1' },
{ lineNo: '1-11-2' },
{ lineNo: '1-11-3' },
{ lineNo: '2' },
{ lineNo: '2-1' },
{ lineNo: '2-2' },
{ lineNo: '2-3' },
{ lineNo: '2-2-1' },
{ lineNo: '2-2-2' },
];
我想要的输出-:
const newData = [
{
lineNo: '1',
children: [{ lineNo: '1-1' }, { lineNo: '1-2' }, { lineNo: '1-3' }, { lineNo: '1-4' }, { lineNo: '1-11' }],
},
{
lineNo: '1-2',
children: [{ lineNo: '1-2-1' }, { lineNo: '1-2-2' }, { lineNo: '1-2-3' }, { lineNo: '1-2-4' }],
},
{
lineNo: '1-3',
children: [{ lineNo: '1-3-1' }, { lineNo: '1-3-2' }, { lineNo: '1-3-3' }],
},
{
lineNo: '1-11',
children: [{ lineNo: '1-11-1' }, { lineNo: '1-11-2' }, { lineNo: '1-11-3' }],
},
{
lineNo: '2',
children: [{ lineNo: '2-1' }, { lineNo: '2-2' }, { lineNo: '2-3' }],
},
{
lineNo: '2-2',
children: [{ lineNo: '2-2-1' }, { lineNo: '2-2-2' }],
},
];
注意:生成的数据必须遵循输出中提到的数字顺序。
到目前为止我做了什么-:
const data = [
{ lineNo: '1' },
{ lineNo: '1-1' },
{ lineNo: '1-2' },
{ lineNo: '1-3' },
{ lineNo: '1-4' },
{ lineNo: '1-11' },
{ lineNo: '1-11-1' },
{ lineNo: '1-11-2' },
{ lineNo: '1-11-3' },
{ lineNo: '1-2-1' },
{ lineNo: '1-2-3' },
{ lineNo: '1-2-2' },
{ lineNo: '1-2-4' },
{ lineNo: '1-2-1-1' },
{ lineNo: '1-2-1-2' },
{ lineNo: '1-2-1-3' },
{ lineNo: '1-3-1' },
{ lineNo: '1-3-2' },
{ lineNo: '1-3-3' },
];
function createTree(data: any) {
const tree: any[] = [];
data.reduce(
(r: any, o: any) => {
o.lineNo
.split('-')
.map((_: any, i: any, a: any) => a.slice(0, i + 1).join('-'))
.reduce((q: any, lineNo: any, i: any, { length }: any) => {
let temp = (q.children = q.children || []).find((p: any) => p.lineNo === lineNo);
if (!temp) {
q.children.push((temp = { lineNo }));
}
if (i + 1 === length) {
Object.assign(temp, o);
}
return temp;
}, r);
return r;
},
{ children: tree }
);
return tree;
}
const createFlat = (data: any) => {
const flat: any[] = [];
const flatData = (data: any) => {
data.forEach((item: any) => {
if (item.children) {
flat.push(item);
flatData(item.children);
}
});
};
flatData(data);
return JSON.parse(JSON.stringify(flat));
};
const getCleanData = (data: any) => {
const cleanData: any[] = [];
function delChildren(obj: any) {
if (obj.children) {
obj.children.forEach((item: any) => {
if (item.children) {
delete item.children;
}
});
}
return obj;
}
data.forEach(function (item: any) {
cleanData.push(delChildren(item));
});
return cleanData;
};
const treeData = createTree(data);
const flatData = createFlat(treeData);
const cleanData = getCleanData(flatData);
console.log(JSON.stringify(cleanData, null, 2));
我正在寻找一种简单明了的方法。
谢谢!
您可以先使用“自然”排序对数据进行排序。 JavaScript localeCompare
有一个选项。
然后创建一个由 lineNo
键控的 Map
并将具有相同 lineNo
属性 和空 children
数组的对象作为相应的值 属性.
然后再次迭代数据以填充那些 children
数组。
提取Map
值并删除那些具有空children
数组的对象,除非它们是top-level节点(边界例)。
这是一个实现:
function createTree(data) {
// Apply natural ordering
data = [...data].sort((a, b) =>
a.lineNo.localeCompare(b.lineNo, "en", { numeric: true })
);
// Create key/value pairs for all lineNo in a Map
let map = new Map(data.map(({lineNo}) => [lineNo, { lineNo, children: [] }]));
// Populate the children arrays
for (let {lineNo} of data) {
map.get(lineNo.replace(/-?\d+$/, ""))?.children?.push({lineNo});
}
// Exclude the nodes that have no children, except if they are top-level
return [...map.values()].filter(({lineNo, children}) =>
!lineNo.includes("-") || children.length
);
}
// Demo
const data = [{ lineNo: '1-1' },{ lineNo: '1-2' },{ lineNo: '1-3-2' },{ lineNo: '1-11-2' },{ lineNo: '1-3' },{ lineNo: '1-11' },{ lineNo: '1-2-3' },{ lineNo: '1-2-2' },{ lineNo: '1' },{ lineNo: '1-2-1' },{ lineNo: '1-2-4' },{ lineNo: '1-11-1' },{ lineNo: '1-3-1' },{ lineNo: '1-4' },{ lineNo: '1-3-3' },{ lineNo: '2-1' },{ lineNo: '2-2' },{ lineNo: '2-2-1' },{ lineNo: '1-11-3' },{ lineNo: '2' },{ lineNo: '2-3' },{ lineNo: '2-2-2' },];
console.log(createTree(data));