将平面对象数组转换为嵌套树(位置数据)
你好,所以我想将给定的平面对象数组(loc.dataset)转换为具有重复键的树状结构。
注意:我的实际输入数据约为 140K 个对象元素,具有完全相同的 4 个键,如下所示。
输入示例:
[
{
"continent_name":"Asia",
"country_name":"Iran",
"subdivision_1_name":"Chaharmahal and Bakhtiari Province",
"city_name":"Lir Abi"
},
{
"continent_name":"Europe",
"country_name":"Cyprus",
"subdivision_1_name":"Ammochostos",
"city_name":"Protaras"
},
{
"continent_name":"Asia",
"country_name":"Iran",
"subdivision_1_name":"West
Azerbaijan Province",
"city_name":"Post"
},
{
"continent_name":"Africa",
"country_name":"Somalia",
"subdivision_1_name":"Bakool",
"city_name":"Oddur"
}
]
输出示例:
[
{
label: "Asia",
children: [
{
label: 'Iran',
children: [
{
label: 'Chaharmahal and Bakhtiari Province',
children: [
{
label: 'Lir Abi',
children: []
}
]
},
{
label: 'West Azerbaijan Province',
children: [
{
label: 'Post',
children: []
}
]
}
]
}
]
},
{
label: "Africa",
children: [
{
label: 'Somalia',
children: [
{
label: 'Bakool',
children: [
{
label: 'Oddur',
children: []
}
]
}
]
}
]
},
{
label: "Europe",
children: [
{
label: 'Cyprus',
children: [
{
label: 'Ammochostos',
children: [
{
label: 'Protaras',
children: []
}
]
}
]
}
]
}
]
这是我试图使用的代码:
const returnTree = []
function unflatten(data, property, returnArr) {
for (let i = 0; i < data.length; i++) {
const currObj = data[i];
const currContinent = data[i][property]
let continentIdx = returnArr.findIndex(obj => obj.label === currContinent)
if (continentIdx === -1) {
continentIdx = returnArr.length
returnArr.push({
'label': currContinent,
'children': [currObj]
})
} else {
returnArr[continentIdx].children.push(currObj)
}
// exceeed max call stack if I continue even one more level in
unflatten(returnArr[continentIdx].children, 'country_name', returnTree)
}
console.log(returnArr)
return returnArr
}
unflatten(inputData, 'continent_name', returnTree)
我遇到的问题是我使用这种递归方法超出了最大调用堆栈,我想知道是否有更好的方法来处理这个问题,也许是迭代?
任何帮助将不胜感激!谢谢你!
Hi so I want to transform a given flat array of objects (loc. dataset) into a tree-like structure with repeating keys.
NOTE: my actual input data is about 140K elements of objects with exactly same 4 keys as listed below.
Input sample:
[
{
"continent_name":"Asia",
"country_name":"Iran",
"subdivision_1_name":"Chaharmahal and Bakhtiari Province",
"city_name":"Lir Abi"
},
{
"continent_name":"Europe",
"country_name":"Cyprus",
"subdivision_1_name":"Ammochostos",
"city_name":"Protaras"
},
{
"continent_name":"Asia",
"country_name":"Iran",
"subdivision_1_name":"West
Azerbaijan Province",
"city_name":"Post"
},
{
"continent_name":"Africa",
"country_name":"Somalia",
"subdivision_1_name":"Bakool",
"city_name":"Oddur"
}
]
Output sample:
[
{
label: "Asia",
children: [
{
label: 'Iran',
children: [
{
label: 'Chaharmahal and Bakhtiari Province',
children: [
{
label: 'Lir Abi',
children: []
}
]
},
{
label: 'West Azerbaijan Province',
children: [
{
label: 'Post',
children: []
}
]
}
]
}
]
},
{
label: "Africa",
children: [
{
label: 'Somalia',
children: [
{
label: 'Bakool',
children: [
{
label: 'Oddur',
children: []
}
]
}
]
}
]
},
{
label: "Europe",
children: [
{
label: 'Cyprus',
children: [
{
label: 'Ammochostos',
children: [
{
label: 'Protaras',
children: []
}
]
}
]
}
]
}
]
And this is the code I was trying to use:
const returnTree = []
function unflatten(data, property, returnArr) {
for (let i = 0; i < data.length; i++) {
const currObj = data[i];
const currContinent = data[i][property]
let continentIdx = returnArr.findIndex(obj => obj.label === currContinent)
if (continentIdx === -1) {
continentIdx = returnArr.length
returnArr.push({
'label': currContinent,
'children': [currObj]
})
} else {
returnArr[continentIdx].children.push(currObj)
}
// exceeed max call stack if I continue even one more level in
unflatten(returnArr[continentIdx].children, 'country_name', returnTree)
}
console.log(returnArr)
return returnArr
}
unflatten(inputData, 'continent_name', returnTree)
The problem I have is I exceed max call stack using this recursive method and I am wondering if there is a better way to handle this, perhaps iteratively?
Any help would be appreciated! Thank you!
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
另一种方法是使用对象作为哈希表和每个子数组的结果集。
Another approach with an object as hash table and result sets for each children array.
我不认为递归是一种可行的方法,因为对于每个属性值(用于生成对象),生成的结构中都存在一个位置。迭代属性时,将最后一个外部数组保留在外部变量中,然后您可以 .find 来查看是否已插入匹配的对象 - 如果尚未插入,则创建一个。
您可以通过将创建的对象保存在地图或按标签索引的对象中,或者首先在对象中创建它们,然后将它们转换为数组来降低复杂性(这将使
O(n)< /code> 将
.find
操作转化为属性查找的O(1)
)。I don't think recursion is the way to go here, because for each property value (to make an object out of), there's exactly one place in the generated structure that it could be. While iterating over properties, keep the last outer array in an outer variable, and you can
.find
to see if a matching object has already been inserted - if it hasn't, then create one.You could decrease the complexity by either saving the created objects in a map or object indexed by label, or by creating them in objects to begin with, then transforming them into an array later (this will turn the
O(n)
operation of.find
intoO(1)
of property lookup).此版本配置了您想要嵌套的键列表,并且它与每个键一起重复。它的递归仅在结果树的级别上。如果存在递归深度问题,那么还有许多更重要的问题需要处理。
This version is configured with the list of keys you want to nest on, and it recurs with each key. It's recursion is only on the levels of the resulting tree. If that has recursion depth problems, then there are many more important problems to deal with. ????
We start with two helper functions:
omitting
returns a copy of an object with the specified key omitted.group
accepts a key-generation function, and returns a function that takes an array of values and groups them into subarrays each of which map to a single key.The main function
labelGroup
takes a list of labels to group upon and returns a function which takes an array of values, and recursively groups these into groups that share a label, mapping the results by extracting the common label, omitting the current key from each, and returning the recursive result of applyinglabelGroup
to them with the remaining keys. The recursion bottoms out when there are no labels left to extract.The only tricky bit of this, is the
filter
call before the recursive application.We use it to remove entirely empty objects. This gives you the results you want when you group on every single label in the objects, as done here, but also allows you to group on a smaller list of labels. So if you passed just
'continent_name'
and'countryName'
, you would get something like this:I think this is a fairly flexible technique. We might make it still more flexible by allowing us to group on composite keys or select multiple fields that show up at each level, and we might make the fields
label
andchildren
configurable. But that's for another day.