我有一个复杂的 json 文件,我必须使用 TypeScript/Javascript 处理它以使其分层,以便以后构建问卷。 json 的每个条目都有一个 Id(唯一)、ParentId(如果是 root,则为 0)、Text、Description。
我的 typescript 界面
export interface Question {
Id: number;
Text: string;
Desc: string;
ParentId: number;
ChildAnswers?: Answer[];
}
export interface Answer {
Id: number;
Text: string;
Desc: string;
ParentId: number;
ChildQuestion?: Question;
}
我可以保证,当对象是一个答案时,它只会有一个 child ,我们可以假设它是一个问题。
平面数据示例:
[
{
Id: 1,
Text: 'What kind of apple is it?',
Desc: '',
ParentId: 0
},
{
Id: 2,
Text: 'Green Apple',
Desc: '',
ParentId: 1
},
{
Id: 3,
Text: 'Red Apple',
Desc: '',
ParentId: 1
},
{
Id: 4,
Text: 'Purple GMO Apple',
Desc: '',
ParentId: 1
},
{
Id: 5,
Text: 'What is the issue with the apple?',
Desc: '',
ParentId: 2
},
{
Id: 6,
Text: 'Spoiled.',
Desc: '',
ParentId: 5
},
{
Id: 7,
Text: 'Taste Bad.',
Desc: '',
ParentId: 5
},
{
Id: 8,
Text: 'Too Ripe.',
Desc: '',
ParentId: 5
},
{
Id: 9,
Text: 'Is not an apple.',
Desc: '',
ParentId: 5
},
{
Id: 10,
Text: 'The apple was not green.',
Desc: '',
ParentId: 5
},
... So on ...
]
我的目标
{
Id: 1,
Text: 'What kind of apple is it?',
Desc: '',
ParentId: 0,
ChildAnswers: [
{
Id: 2,
Text: 'Green Apple',
Desc: '',
ParentId: 1,
ChildQuestion: {
Id: 5,
Text: 'What is the issue with the apple?',
Desc: '',
ParentId: 2,
ChildAnswers: [
{
Id: 6,
Text: 'Spoiled.',
Desc: '',
ParentId: 5,
... So on ...
},
{
Id: 7,
Text: 'Taste Bad.',
Desc: '',
ParentId: 5,
... So on ...
},
{
Id: 8,
Text: 'Too Ripe.',
Desc: '',
ParentId: 5,
... So on ...
},
{
Id: 9,
Text: 'Is not an apple.',
Desc: '',
ParentId: 5,
... So on ...
},
{
Id: 10,
Text: 'The apple was not green.',
Desc: '',
ParentId: 5,
... So on ...
},
... So on ...
]
}
},
{
Id: 3,
Text: 'Red Apple',
Desc: '',
ParentId: 1,
... So on ...
},
{
Id: 4,
Text: 'Red Apple',
Desc: '',
ParentId: 1,
... So on ...
}
... So on ...
]
}
我目前正在使用我在 stackoverflow 上找到的这个 list_to_tree 函数,我只是不知道如何区分问题和答案。我应该只检查问题的长度是一个还是以奇数间隔标记它?:
function list_to_tree(list) {
var map = {}, node, roots = [], i;
for (i = 0; i < list.length; i += 1) {
map[list[i].Id] = i; // initialize the map
list[i].Children = []; // initialize the children
}
for (i = 0; i < list.length; i += 1) {
node = list[i];
if (node.ParentId !== 0) {
// if you have dangling branches check that map[node.ParentId] exists
list[map[node.ParentId]].Children.push(node);
} else {
roots.push(node);
}
}
return roots;
}
最佳答案
这里有一个暴力解决问题的方法:
var flat = [
{
Id: 1,
Text: 'What kind of apple is it?',
Desc: '',
ParentId: 0
},
{
Id: 2,
Text: 'Green Apple',
Desc: '',
ParentId: 1
},
{
Id: 3,
Text: 'Red Apple',
Desc: '',
ParentId: 1
},
{
Id: 4,
Text: 'Purple GMO Apple',
Desc: '',
ParentId: 1
},
{
Id: 5,
Text: 'What is the issue with the apple?',
Desc: '',
ParentId: 2
},
{
Id: 6,
Text: 'Spoiled.',
Desc: '',
ParentId: 5
},
{
Id: 7,
Text: 'Taste Bad.',
Desc: '',
ParentId: 5
},
{
Id: 8,
Text: 'Too Ripe.',
Desc: '',
ParentId: 5
},
{
Id: 9,
Text: 'Is not an apple.',
Desc: '',
ParentId: 5
},
{
Id: 10,
Text: 'The apple was not green.',
Desc: '',
ParentId: 5
},
]
// first get the roots
const tree = flat.filter((question) => question.ParentId === 0);
// Next we are going to call alternating methods recursively.
function populateQuestionChildren(node) {
const { Id } = node;
flat.forEach((answer) => {
if (answer.ParentId === Id) {
if (!node.ChildAnswers) {
node.ChildAnswers = [];
}
node.ChildAnswers.push(answer);
populateAnswerChildren(answer);
}
});
}
function populateAnswerChildren(node) {
const { Id } = node;
flat.forEach((question) => {
if (question.ParentId === Id) {
if (!node.ChildQuestions) {
node.ChildQuestions = [];
}
node.ChildQuestions.push(question);
populateQuestionChildren(question);
}
});
}
// Kick off the build for each question tree.
tree.forEach((question) => {
populateQuestionChildren(question);
});
很可能有更优雅的解决方案 - 但鉴于这将只有几十个或几百个问题/答案 - 这应该能满足您的需求。
[编辑]
我使用了您的接口(interface)并发现我的代码存在问题。 Answer 对象上只有一个“ChildQuestion”。所以这是我对 TypeScript 的更改,以使其正常工作。希望对您有所帮助:
interface Question {
Id: number;
Text: string;
Desc: string;
ParentId: number;
ChildAnswers ? : Answer[];
}
interface Answer {
Id: number;
Text: string;
Desc: string;
ParentId: number;
ChildQuestion ? : Question;
}
// first get the roots
const tree = flat.filter((question) => question.ParentId === 0);
function populateQuestionChildren(node: Question) {
const { Id } = node;
flat.forEach((answer) => {
if (answer.ParentId === Id) {
if (!node.ChildAnswers) {
node.ChildAnswers = [];
}
node.ChildAnswers.push(answer);
populateAnswerChild(answer);
}
});
}
function populateAnswerChild(answer: Answer) {
const { Id } = answer;
// switch to every so we can break early once a question is found.
flat.every((node) => {
if (node.ParentId === Id) {
answer.ChildQuestion = node;
populateQuestionChildren(node);
return false;
}
return true;
});
}
tree.forEach((question) => {
populateQuestionChildren(question);
});
关于javascript - 在 Typescript/JavaScript 中从平面数组构建树数组,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58979347/