[英]How to convert sync and async recursive function to iteration in JavaScript
[英]Convert a recursive function to an iteration in javascript
我無法將遞歸函數轉換為迭代。 考慮以下功能 :
function getTreeDataFromRows (id, rows) {
let ret_val = []
for (let i = 0; i < rows.length; i++) {
let row = rows[i]
if (id == row.id_parent) {
let new_element = {
id: row.id,
id_parent: row.id_parent,
value: row.value,
data: getTreeDataFromRows(row.id, rows)
}
for (let property in row) {
if ('id' == property || 'id_parent' == property || 'value' == property) {
continue
}
new_element[property] = row[property]
}
ret_val.push(new_element)
}
}
return ret_val
}
我有一個類似於以下內容的json作為輸入 :
[{
"id": "c-1",
"id_parent": null,
"value": "Chapter 1"
},
{
"id": "a-1",
"id_parent": "c-1",
"value": "Article 1.1"
},
{
"id": "a-2",
"id_parent": "c-1",
"value": "Article 1.2"
},
{
"id": "c-2",
"id_parent": null,
"value": "Chapter 2"
},
{
"id": "a-21",
"id_parent": "c-2",
"value": "Article 2.1"
},
{
"id": "a-22",
"id_parent": "c-2",
"value": "Article 2.2"
},
{
"id": "a-221",
"id_parent": "a-22",
"value": "Quote 221 from article 2.2"
},
{
"id": "a-222",
"id_parent": "a-22",
"value": "Quote 222 from article 2.2"
}
]
輸出必須是這樣的:
[{
"id": "c-1",
"id_parent": null,
"value": "Chapter 1",
"data": [{
"id": "a-1",
"id_parent": "c-1",
"value": "Articole 1.1",
"data": []
},
{
"id": "a-2",
"id_parent": "c-1",
"value": "Articole 1.2",
"data": []
}
]
},
{
"id": "c-2",
"id_parent": null,
"value": "Chapter 2",
"data": [{
"id": "a-21",
"id_parent": "c-2",
"value": "Articole 2.1",
"data": []
},
{
"id": "a-22",
"id_parent": "c-2",
"value": "Articole 2.2",
"data": [{
"id": "a-221",
"id_parent": "a-22",
"value": "Quote 221 from article 2.2",
"data": []
},
{
"id": "a-222",
"id_parent": "a-22",
"value": "Quote 222 from article 2.2",
"data": []
},
]
},
]
}
]
樹表需要此輸出。 當處理大量數據時,遞歸函數會給出“超出最大調用堆棧大小”錯誤。 樹也可以有很多子代(兒子,孫子等)。 我嘗試使用堆棧數組編寫一個for循環,但未成功。 我很困惑,我的代碼也可能造成混亂。
function functionWithIteration (rows) {
var my_stack = [null]
var final_val = []
while( my_stack.length > 0 ) {
var ret_val = []
var first_time = true
var id = my_stack.pop()
var temp_val = []
for (let i = 0; i < rows.length; i++) {
var row = rows[i]
var signal = true
if (id == row.id_parent) {
signal = false
var new_element = {
id: row.id,
id_parent: row.id_parent,
value: row.value,
data: []
}
for (let property in row) {
if (property == 'id' || property == 'id_parent' || property == 'value') {
continue
}
new_element[property] = row[property]
}
if (first_time){
ret_val.push(new_element)
first_time = false
}
else {
ret_val[ret_val.length - 1].data.push(new_element)
}
}
if ( signal) {
temp_val.push(ret_val)
my_stack.push(row.id)
}
}
final_val.push(temp_val)
}
return final_val
}
任何幫助將不勝感激! 謝謝!
您可以對已知ID和父對象使用對象的單循環方法。
此解決方案不希望數據按排序順序。
var data = [{ id: "c-1", id_parent: null, value: "Chapter 1" }, { id: "a-1", id_parent: "c-1", value: "Article 1.1" }, { id: "a-2", id_parent: "c-1", value: "Article 1.2" }, { id: "c-2", id_parent: null, value: "Chapter 2" }, { id: "a-21", id_parent: "c-2", value: "Article 2.1" }, { id: "a-22", id_parent: "c-2", value: "Article 2.2" }, { id: "a-221", id_parent: "a-22", value: "Quote 221 from article 2.2" }, { id: "a-222", id_parent: "a-22", value: "Quote 222 from article 2.2" }], tree = function (data, root) { var o = {}; data.forEach(function (a) { if (o[a.id] && o[a.id].children) { a.children = o[a.id].children; } o[a.id] = a; o[a.id_parent] = o[a.id_parent] || {}; o[a.id_parent].children = o[a.id_parent].children || []; o[a.id_parent].children.push(a); }); return o[root].children; }(data, null); console.log(tree);
.as-console-wrapper { max-height: 100% !important; top: 0; }
一旦弄清楚保存對對象的引用的簡單步驟,這是一個相當簡單的解決方案。 遍歷數組並創建一個以元素id為鍵的對象。 然后,您要使用該元素來引用元素以添加其子元素。
var data = [{ "id": "c-1", "id_parent": null, "value": "Chapter 1" }, { "id": "a-1", "id_parent": "c-1", "value": "Article 1.1" }, { "id": "a-2", "id_parent": "c-1", "value": "Article 1.2" }, { "id": "c-2", "id_parent": null, "value": "Chapter 2" }, { "id": "a-21", "id_parent": "c-2", "value": "Article 2.1" }, { "id": "a-22", "id_parent": "c-2", "value": "Article 2.2" }, { "id": "a-221", "id_parent": "a-22", "value": "Quote 221 from article 2.2" }, { "id": "a-222", "id_parent": "a-22", "value": "Quote 222 from article 2.2" } ] // we use reduce to loop over the object to build up our new object. var result = data.reduce((obj, itm) => { // store it into a obj so we can reference it obj.temp[itm.id] = itm // check to see if we have a parent if (itm.id_parent) { // if we have a parent see if data is set yet // if not, set it to an empty array obj.temp[itm.id_parent].data = obj.temp[itm.id_parent].data || [] // push the child into the parent obj.temp[itm.id_parent].data.push(obj.temp[itm.id]) } else { // If we have no parent, than it is a root element // or we push it into an array to keep track of it obj.order.push(obj.temp[itm.id]) } // return the object for reduces next iteration return obj }, { temp:{}, order:[]}) // init recude with an empty object and array .order // return the order console.log(result)
該解決方案期望父母出現在他們的孩子之前。 如果不是這種情況,那么您可以做幾件事。 無論哪種方式,您都會創建一個“臨時”對象,直到找到真正的對象為止。
我認為您的邏輯有誤。 當它遞歸時,它似乎從頭開始。 直觀地講,這將使遞歸實例陷入與之前完全相同的條件,從而無限遞歸。 (就邏輯而言,循環變量i
多個嵌套實例具有相同的值。)
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.