我想创建一个可以处理条件/分支的JSON对象。具体来说,我有如下工作流程:
对于第1步,用户有三个选择,根据他们的选择,他们会在步骤2中看到不同的选择。同样的逻辑延伸到第3步等。
理想情况下,我希望以JSON格式获取所有这些数据,以便我可以根据用户的选择进行循环,找出接下来要向他们提出的选择。
有没有办法以允许我这样做的方式构造JSON对象(或者可能只是一个数组)?
我应该提一下,我希望它足够灵活,以便如果我稍后决定改变一个步骤的选择数量,那么我所要做的就是修改JSON对象/数组(模型),而不必修改循环通过对象/数组的逻辑。
非常感谢。
答案 0 :(得分:8)
您正在构建的内容本质上是一种树数据结构。我建议从原始的节点对象构建它,而不是包含对同一类型的子对象的递归引用。只使用这种类型的对象就可以实现完全树,其中“最顶层”对象称为根对象,其中所有用户都开始进行选择。从根开始,用户选择子节点,直到它们到达没有子节点的叶节点,即从那里无法进一步选择。
所有节点都是这样的对象:
{
"label": "Choice A",
"question": "Choose subselection?",
"children": [ (array of more objects of the same type) ]
}
如果label
是您要为此选项指定的名称/标签,question
是用户必须回答以选择下一个子节点的下一个问题,children
是一个数组更多相同类型的节点,其中每个子节点label
是该节点question
的一个可能答案。
为了举例说明,让我们假设以下选择树,可以在想象中的在线零售商店中询问,它只销售两种主要类型的产品:服装和食品。在服装部分,有牛仔裤,T恤和不同颜色的连帽衫(为简单起见,我们假设我们已经知道客户的尺寸。)商店还提供少量类型的帽子。在食品部分,有拉面,不同口味的苏打水和香蕉。在服装部分,顾客可以在他们的黑色T恤上印上电视节目或摇滚乐队的标志,或者只买一件没有标志的黑色T恤。电视节目的标志还可以印在蓝色连帽衫上,或者顾客可以选择购买没有标志的蓝色连帽衫。
因此,面向客户的答案/问题对的决策树如下:
A: <start>
Q: What product category?
|
|--A: Clothes
| Q: What type of clothing?
| |
| |--A: Jeans
| | Q: Color of jeans?
| | |
| | |--A: Blue
| | | Q: <end>
| | |
| | |--A: Black
| | | Q: <end>
| | |
| | \--A: White
| | Q: <end>
| |
| |--A: Shirt
| | Q: Type of shirt?
| | |
| | |--A: T-shirt
| | | Q: Color of T-shirt?
| | | |
| | | |--A: Red
| | | | Q: <end>
| | | |
| | | |--A: Green
| | | | Q: <end>
| | | |
| | | |--A: Black
| | | | Q: Logo?
| | | | |
| | | | |--A: Rock band
| | | | | Q: <end>
| | | | |
| | | | |--A: TV show
| | | | | Q: <end>
| | | | |
| | | | \--A: No logo
| | | | Q: <end>
| | | |
| | | \--A: Orange
| | | Q: <end>
| | |
| | \--A: Hoodie
| | Q: Color of hoodie?
| | |
| | |--A: Gray
| | | Q: <end>
| | |
| | |--A: Blue
| | | Q: Logo for hoodie?
| | | |
| | | |--A: TV show
| | | | Q: <end>
| | | |
| | | \--A: No logo
| | | Q: <end>
| | |
| | |--A: Green
| | | Q: <end>
| | |
| | |--A: Pink
| | | Q: <end>
| | |
| | |--A: Brown
| | | Q: <end>
| | |
| | |--A: Black
| | | Q: <end>
| | |
| | \--A: Red
| | Q: <end>
| |
| \--A: Hat
| Q: Type of hat?
| |
| |--A: Stetson
| | Q: <end>
| |
| \--A: Sombrero
| Q: <end>
|
\--A: Food
Q: Type of food?
|
|--A: Ramen noodles
| Q: <end>
|
|--A: Soda pop
| Q: Flavor
| |
| |--A: Cola
| |--Q: <end>
| |
| |--A: Lemon
| |--Q: <end>
| |
| |--A: Orange
| |--Q: <end>
| |
| |--A: Apple
| \--Q: <end>
|
\--A: Bananas
Q: <end>
客户从“回答”<start>
开始,选择多项选择题,直到他们到达具有特殊“问题”<end>
的节点。
当我们将此树映射到JSON时,询问用户感兴趣的产品类别(衣服/食品)的根问题(上面的<start>
)可以具有标签值null
,因为它不是任何其他问题的答案(孩子)。它是整个结构的第一个对象,所有其他节点都是它的子节点。通过使用<end>
代替null
字符串和question
数组,可以指示无法进一步选择(上面children
)的叶节点。所有其他节点指定标签字符串(节点“回答”的顶级问题),下一个问题以及问题的可能答案数组:
{
"label": null,
"question": "What product category?",
"children": [
{
"label": "Clothes",
"question": "What type of clothing?",
"children": [
{
"label": "Jeans",
"question": "Color of jeans?",
"children": [
{
"label": "Blue",
"question": null,
"children": null
},
{
"label": "Black",
"question": null,
"children": null
},
{
"label": "White",
"question": null,
"children": null
}
]
},
{
"label": "Shirt",
"question": "Type of shirt?",
"children": [
{
"label": "T-Shirt",
"question": "Color of T-shirt?",
"children": [
{
"label": "Red",
"question": null,
"children": null
},
{
"label": "Green",
"question": null,
"children": null
},
{
"label": "Black",
"question": "Logo?",
"children": [
{
"label": "Rock band",
"question": null,
"children": null
},
{
"label": "TV show",
"question": null,
"children": null
},
{
"label": "No logo",
"question": null,
"children": null
}
]
},
{
"label": "Orange",
"question": null,
"children": null
}
]
},
{
"label": "Hoodie",
"question": "Color of hoodie?",
"children": [
{
"label": "Gray",
"question": null,
"children": null
},
{
"label": "Blue",
"question": null,
"children": [
{
"label": "TV show",
"question": null,
"children": null
},
{
"label": "No logo",
"question": null,
"children": null
}
]
},
{
"label": "Green",
"question": null,
"children": null
},
{
"label": "Pink",
"question": null,
"children": null
},
{
"label": "Brown",
"question": null,
"children": null
},
{
"label": "Black",
"question": null,
"children": null
},
{
"label": "Red",
"question": null,
"children": null
}
]
},
{
"label": "White",
"question": null,
"children": null
}
]
},
{
"label": "Hat",
"question": "Type of hat?",
"children": [
{
"label": "Stetson",
"question": null,
"children": null
},
{
"label": "Sombrero",
"question": null,
"children": null
}
]
}
]
},
{
"label": "Food",
"question": "Type of food?",
"children": [
{
"label": "Ramen noodles",
"question": null,
"children": null
},
{
"label": "Soda pop",
"question": null,
"children": [
{
"label": "Cola",
"question": null,
"children": null
},
{
"label": "Lemon",
"question": null,
"children": null
},
{
"label": "Orange",
"question": null,
"children": null
},
{
"label": "Apple",
"question": null,
"children": null
}
]
},
{
"label": "Bananas",
"question": null,
"children": null
}
]
}
]
}
以上是100%有效的JSON:您可以将其复制并粘贴到JSONtree以逐级调查其结构。
故事的士气是,这种可能非常复杂的可用用户选择和路径系统,可以在其核心(带有叶子的节点)上以令人惊讶的简单数据结构实现。复杂性源于您在节点之间定义的 relationship 。
答案 1 :(得分:0)
用JSON表达你的树结构是微不足道的。每个问题节点中的路径选择集是一个问题节点数组。这是一种经典的递归数据结构。
在您的JSON中执行此操作,然后在其旁边添加另一个分支,这是数组中的一系列决策点选择:[3,1,2],表示树中的路径,来自树的根到叶子:在根目录,选择选项3;在您通过以下选项3到达的节点处,选择选项1;在该节点,选择选项2.你在那里。这是一个通过选择数组的简单循环。 choices数组中每个整数的含义取决于前一个发送给您的路径段。它是一个表示为数据结构的状态机:当您遍历树时,当前节点是您的状态,而choice-path数组中的下一个数字是您的输入。
我开始编号为1,因为你做了 - 但请记住,JavaScript中的数组开始在ZERO索引,而不是1.数组a中的第一项是[0],而不是[1]。
var json = JSON.parse(thingy);
var choices = json.Choices; // array of user choices
var curNode = json.Tree; // root of the tree
for ( var i = 0; i < choices.length; ++i ) {
// Do whatever you need to with the current node
curNode = curNode.Children[choices[i]];
}
但是当然要添加大量的范围检查!
它没有任何收获,并且增加了混淆,试图在相同的数据结构中表达树和通过树的路径 - 如果这甚至是你正在考虑的事情。
答案 2 :(得分:0)
有很多方法可以满足您的需求,最合适的方法取决于您的数据。一个例子如下:
var obj = {
"data" : "First question, two options",
"options" : [
{
"data" : "Option1, Second question, three options",
"options" : [
{ "data" : "Fail" },
{ "data" : "Success" },
{ "data" : "Fail" }
]
}, {
"data" : "Option2, Second question, four options",
"options" : [
{ "data" : "Fail" },
{
"data" : "Option2.2, Third question, two options",
"options" : [
{ "data" : "Fail" },
{ "data" : "Success" }
]
},
{ "data" : "Success" },
{ "data" : "Fail" }
]
}
]
}
注意:我是手工编写的,这个例子只是为了给你一个大概,我还没有验证JSON。