可能重复,但这个与其他问题不同,不希望将对象挂钩到另一个。我想创建一个包含层次结构数据的新对象/数组
所以我有这些数据集:
var sets = {
'dataSet1': {
'ID': '1',
'ParentID': '0'
},
'dataSet2': {
'ID': '2',
'ParentID': '1'
},
'dataSet3': {
'ID': '3',
'ParentID': '1'
},
'dataSet4': {
'ID': '4',
'ParentID': '3'
}
}
我想循环遍历它们并使用ID和ParentID动态创建层次结构。我希望输出的过程结果如下:
var tiers = {
'tier1':[
{
'parentid':'0',
'id':'1'
}
]
,'tier2':[
{
'parentid':'1',
'id':'2'
},
{
'parentid':'1',
'id':'3'
}
]
,'tier3':[
{
'parentid':'3',
'id':'4'
}
]
}
基本上,层对象将包含包含具有id和父id字段的对象的层数组。
因此,当我访问数据时,我所要做的就是通过层[' tier2'] [1]获取它们。我需要做的就是将数据结构化为层次结构。注意:原生js
这是我目前的尝试,但这只适用于层次结构顶部的那个,第二层及以下是最大的问题
var datasetobj = sets;
var hierarchy = tiers;
for (x in datasetobj) {
if (datasetobj[x]['ParentID'] == 0) {
hierarchy['tier1'].push({
'parentid': datasetobj[x]['ParentID'],
'id': datasetobj[x]['ID']
});
}
}
现在,如果我要通过限制程序可以处理的层数来使用静态方法,然后检查每个ID然后插入层,这是相当容易的。但这并不完全是OOP的做法。
答案 0 :(得分:1)
for循环中if条件的问题。它只会处理顶级元素if (datasetobj[x]['ParentID'] == 0) only processes parent id 0
。
在动态创建层次结构数组并删除if条件后获取您的内容。做类似的事情:
var tiers = {};
var sets = {
'dataSet1': {
'ID': '1',
'ParentID': '0'
},
'dataSet2': {
'ID': '2',
'ParentID': '1'
},
'dataSet3': {
'ID': '3',
'ParentID': '1'
},
'dataSet4': {
'ID': '4',
'ParentID': '3'
}
};
var datasetobj = sets;
var hierarchy = tiers;
for (x in datasetobj) {
if (datasetobj[x]['ParentID']) {
var idx = 'tier'+datasetobj[x]['ParentID'];
if(!hierarchy[idx])
hierarchy[idx]=[];
hierarchy[idx].push({
'parentid': datasetobj[x]['ParentID'],
'id': datasetobj[x]['ID']
});
}
};
console.log(tiers);

答案 1 :(得分:1)
您的问题需要遍历您的依赖关系树,同时跟踪深度。您可以使用使用递归和递增深度的简单depth-first-traversal来解决问题。
我不得不为缺乏解释而道歉。如果您以后需要,我会添加更多详细信息,但我必须运行。希望这有助于解决您的问题。如果您需要更多解释,请告诉我。
我还在层对象中添加了originalKey
属性,因此您可以使用originalKey
访问原始对象。
更新:好的,你想要更多的解释,你会得到更多的解释。我也改变了我的实现速度。
另外,您能提供一些链接,我可以在哪里学习这些概念吗?你的方法对我来说很新鲜
这个问题只能通过recursion和一些基本的计算机科学概念来解决。我将解释代码,并提供一些良好的计算机科学概念链接。这些概念并不复杂。这些是你在计算机科学本科课程中首先学到的东西。
sets
转换为hashMap
我要做的第一件事就是将您的sets
对象转换为另一个我正在调用hashMap
的对象。我正在将它转换为这种形式,因为它会使"查找"我们创建tier
对象时速度更快。
以下是sets
对象供参考:
const sets = {
'dataSet1': {
'ID': '1',
'ParentID': '0'
},
'dataSet2': {
'ID': '2',
'ParentID': '1'
},
'dataSet3': {
'ID': '3',
'ParentID': '1'
},
'dataSet4': {
'ID': '4',
'ParentID': '3'
}
};
我执行此转换:
const hashMap = (Object
// 1
.keys(sets)
// 2
.map(datasetKey => ({
originalKey: datasetKey,
id: sets[datasetKey].ID,
parentId: sets[datasetKey].ParentID
}))
// 3
.reduce((hashMap, value) => {
// 4
const hashMapKey = 'hasParentId' + value.parentId;
// 5
if (hashMap[hashMapKey] === undefined) {
hashMap[hashMapKey] = [];
}
// 6
hashMap[hashMapKey].push(value);
// 7
return hashMap;
}, {})
);
导致此对象:
{
"hasParentId0": [
{
"originalKey": "dataSet1",
"id": "1",
"parentId": "0"
}
],
"hasParentId1": [
{
"originalKey": "dataSet2",
"id": "2",
"parentId": "1"
},
{
"originalKey": "dataSet3",
"id": "3",
"parentId": "1"
}
],
"hasParentId3": [
{
"originalKey": "dataSet4",
"id": "4",
"parentId": "3"
}
]
}
一步一步:
Object.keys
从对象sets
Array.prototype.map
将数组创建的每个键从调用Object.keys
映射到新对象。该对象有3个属性:originalKey
,id
,parentId
Array.prototype.reduce
将映射对象数组(在上一步中创建)缩减为单个对象。 Array.prototype.reduce
的第一个参数是" reducer"带两个参数的函数。 " reducer"的第一个参数函数是一个"累加器"第二个参数是数组中的一个项目。 reducer将被多次调用,一次调用数组中的每个项目。 reducer函数返回一个累加器,该累加器将在下一个内部函数的调用中使用(因此数组的所有项都减少到累加器中)。 Array.prototype.reduce
的第二个参数是初始累加器。在这种情况下,初始累加器是一个空对象{}
。hashMapKey
。该字符串将用作累加器的键。hashMap[hashMapKey]
都是一个数组。在这里,我们检查hashMap[hashMapKey]
的值是否为数组,如果不是,我们将其设为一个。hashMap[hashMapKey]
处有一个数组,我们可以在该数组上推送value
。请记住,value
是我们从第2步映射的对象。hashMap
以用作"累加器"下一个"减速机"调用缩减完成后,hashMap
包含正确的转换。在下一步中快速查找需要转换为sets
到hashMap
。
hashMap
转换为tier
这就是计算机科学思想的用武之地。上面的结构有一个隐含的graph,其中每个节点(也就是点)都是来自sets
的对象,每个边缘都是通过属性的有向关系ParentID
。
为了创建您想要的结构,您需要执行depth-first-traversal遍历此图表,同时跟踪深度。
以下是代码:
// 1
const tier = {};
let maxDepth = 0;
// 2
function traverse(currentParentId, depth) {
// 3
if (depth > maxDepth) {
maxDepth = depth;
}
// 4
const childrenOfCurrentParent = hashMap['hasParentId' + currentParentId]
// 5
if (childrenOfCurrentParent === undefined) {
return;
}
// 6
childrenOfCurrentParent.forEach(value => {
// 7
const tierKey = 'tier' + depth;
if (tier[tierKey] === undefined) {
tier[tierKey] = [];
}
// 8
tier[tierKey].push(value);
// 9
traverse(value.id, depth + 1);
});
}
traverse
,它带有两个参数:currentParentId
和depth
。 currentParentId
是用于标识当前父级的id的密钥。 此函数最初使用currentParentId
0
和depth
0
来调用。一旦我们查看实现,这将更有意义代码。maxDepth
childrenOfCurrentParent
。看看我们为什么做到了?在此表中查找值非常快:)childrenOfCurrentParent
,请不要做任何事情。Array.prototype.forEach
遍历childrenOfCurrentParent
。 value
再次是转换中映射对象的value
。tierKey
以存储value
。如果数组未初始化,请将其初始化。value
traverse
功能,更改currentParrentId
并递增depth
。从第3步开始重复,直到没有更多项目被放置。这基本上是深度优先遍历tier
转换为tierArray
我认为这个是不言自明的。由于层是一组有序项,因此最好将其存储在数组中。这就是我们跟踪maxDepth
。
const sets = {
'dataSet1': {
'ID': '1',
'ParentID': '0'
},
'dataSet2': {
'ID': '2',
'ParentID': '1'
},
'dataSet3': {
'ID': '3',
'ParentID': '1'
},
'dataSet4': {
'ID': '4',
'ParentID': '3'
}
};
// `hashMap` is a data transform
// see the `console.log` of this transform
const hashMap = (Object
// grab the keys of the object `sets`
.keys(sets)
// then map every key to a new object
.map(datasetKey => ({
originalKey: datasetKey,
id: sets[datasetKey].ID,
parentId: sets[datasetKey].ParentID
}))
// reduce the new objects into a single object
.reduce((hashMap, value) => {
// create a key to store the `value`
const hashMapKey = 'hasParentId' + value.parentId;
// if `hashMap[hashMapKey]` isn't intialized yet,
// initialize it to an array
if (hashMap[hashMapKey] === undefined) {
hashMap[hashMapKey] = [];
}
// then push the value (the objects created above)
hashMap[hashMapKey].push(value);
// return the hashMap
return hashMap;
}, {})
);
console.log('hashMap', hashMap);
// create an object to store the `tier`s in.
const tier = {};
// keep track of the `maxDepth` in case you want to transform `tier` to an array
let maxDepth = 0;
// this is a recursive function to traverse your graph
// this implements a depth-first-traversal keeping track of the `depth`
function traverse(currentParentId, depth) {
if (depth > maxDepth) {
maxDepth = depth;
}
const childrenOfCurrentParent = hashMap['hasParentId' + currentParentId]
// if there are no children of the currentParent
if (childrenOfCurrentParent === undefined) {
return;
}
childrenOfCurrentParent.forEach(value => {
const tierKey = 'tier' + depth;
if (tier[tierKey] === undefined) {
tier[tierKey] = [];
}
tier[tierKey].push(value);
traverse(value.id, depth + 1);
});
}
// call the function to start the traversal
// using 0 as the first `currentParentId` and
// using 0 as the first `depth` value
traverse(0, 0);
// the tier object is now created
console.log('tier', tier);
// but it might be more natural to have `tier` as an array
const tierArray = [];
for (let i = 0; i < maxDepth; i += 1) {
tierArray[i] = tier['tier' + i];
}
console.log('tierArray', tierArray);
&#13;
P,嗯,这是什么答案。希望这有帮助!