我在使用 vuejs 的專案上遇到問題。我有一個這樣的嵌套物件陣列:
資料
data: [
{
"id":1,
"parent_id":null,
"title":"First folder",
"children":[
{
"id":3,
"parent_id":1,
"title":"First folder in parents",
"children":[]
},
{
"id":4,
"parent_id":1,
"title":"Second folder in parents",
"children":[
{
"id":5,
"parent_id":4,
"title":"test",
"children":[]
}
],
}
]
},
{
"id":2,
"parent_id":null,
"title":"Second folder",
"children":[],
}
]
我想在計算屬性中獲取特定 id 的所有父母的陣列
computed: {
parents() {
this.getAllParents(data, currentId);
},
},
我的功能
getParents(array, id, parentsId) {
for (let i = 0; i < array.length; i ) {
const child = array[i];
if (child.id === id && ((child.children.length > 0 && child.children.some((el) => el.id === parentsId)) || !parentsId)) {
return [child];
} if (child.children.length > 0) {
const x = this.getParents(child.children, child.id, id);
if (x) return Array.isArray(x) ? [child, ...x] : [child, x];
}
}
return [];
},
例如,如果我的 currentId 是 3,我希望在我的計算中這樣:
[
{"id": 1, "parent_id": null....},
{"id": 3, "parent_id": 1....}
]
如果我的 currentId 是 1,我想要這個:
[
{"id": 1, "parent_id": null....},
]
如果我的 currentId 是 5,我想要這個:
[
{"id": 1, "parent_id": null....},
{"id": 4, "parent_id": 1....},
{"id": 5, "parent_id": 4....},
]
現在,我的功能
return [
{"id": 1, "parent_id": null....},
{"id": 4, "parent_id": 1....}
]
如果我當前的 id 是 3,而不是 id:3,我不明白為什么
請問這個怎么做?
謝謝
uj5u.com熱心網友回復:
您可以遞回回圈子陣列并繼續收集父母。
請參考以下解決方案:
const data = [
{
id: 1,
parent_id: null,
title: "First folder",
children: [
{ id: 3, parent_id: 1, title: "First folder in parents", children: [] },
{
id: 4,
parent_id: 1,
title: "Second folder in parents",
children: [{ id: 5, parent_id: 4, title: "test", children: [] }],
},
],
},
{ id: 2, parent_id: null, title: "Second folder", children: [] },
];
const getAncestors = (target, children, ancestors = []) => {
for (let node of children) {
if (node.id === target) {
return ancestors.concat(node.id);
}
const found = getAncestors(target, node.children, ancestors.concat(node.id));
if (found) {
return found;
}
}
return undefined;
};
console.log(getAncestors(5, data));
注意:為簡潔起見,我剛剛推送了ids,您可以更新解決方案以推送整個節點。
uj5u.com熱心網友回復:
通用查找
遞回是一種函式式遺產,因此通過使用函式式樣式,我們可以得到最好的結果。您的代碼非常好,但還有一些改進的余地。通過分解問題,我們可以隔離關注點,并使我們更容易為較小的子問題撰寫單獨的解決方案。
我們從使用函式find(t, func)搜索的高階開始,并回傳匹配節點的所有路徑。tfunc
- if
t是一個陣列,對于所有child的trecur 子問題find(child, func) - (inductive)
t不是陣列。如果t是一個物件,那么如果用戶提供的函式回傳 true forf,則產生單例輸出,[t]否則對于每個path子問題find(t.children, func),t添加到path和 yield。 - (inductive)
t既不是陣列也不是物件。停止迭代。
// find (node array ∪ node, (node -> boolean)) -> (node array) generator
function* find(t, func) {
switch (true) {
case is(t, Array): // 1
for (const child of t)
yield* find(child, func)
break
case is(t, Object): // 2
if (Boolean(func(t)))
yield [t]
else for (const path of find(t.children, func))
yield [t, ...path]
break
default: // 3
return
}
}
這取決于is-
function is(t, T) {
return t?.constructor === T
}
專門的發現
寫作findById是一門專長的事find。我們假設id是唯一的,因此return到第一個匹配節點的路徑(如果有)。否則回傳空路徑,[].
// findById : (node array ∪ node, number) -> node array
function findById(t, id) {
for (const path of find(t, node => node.id === id))
return path
return []
}
演示
為了演示正確的行為,我撰寫了一個demo函式,從回傳的節點中洗掉一些欄位。這使我們能夠輕松地確認輸出 -
function demo(t, id) {
console.log(
`== id: ${id} ==`,
JSON.stringify(
findById(data, id).map(p =>
({ id: p.id, parent_id: p.parent_id, title: p.title })
)
)
)
}
demo(data, 1)
demo(data, 3)
demo(data, 5)
== id: 1 == [{"id":1,"parent_id":null,"title":"First folder"}]
== id: 3 == [{"id":1,"parent_id":null,"title":"First folder"},{"id":3,"parent_id":1,"title":"First folder in parents"}]
== id: 5 == [{"id":1,"parent_id":null,"title":"First folder"},{"id":4,"parent_id":1,"title":"Second folder in parents"},{"id":5,"parent_id":4,"title":"test"}]
您可以驗證下面的輸出 -
function is(t, T) {
return t?.constructor === T
}
function* find(t, func) {
switch (true) {
case is(t, Array):
for (const child of t)
yield* find(child, func)
break
case is(t, Object):
if (Boolean(func(t)))
yield [t]
else
for (const path of find(t.children, func))
yield [t, ...path]
break
default:
return
}
}
function findById(t, id) {
for (const path of find(t, node => node.id === id))
return path
return []
}
function demo(t, id) {
console.log(`== id: ${id} ==`, JSON.stringify(findById(data, id).map(p =>
({ id: p.id, parent_id: p.parent_id, title: p.title })
)))
}
const data = [{id:1,parent_id:null,title:"First folder",children:[{id:3,parent_id:1,title:"First folder in parents",children:[]},{id:4,parent_id:1,title:"Second folder in parents",children:[{id:5,parent_id:4,title:"test",children:[]}],}]},{id:2,parent_id:null,title:"Second folder",children:[]}]
demo(data, 1)
demo(data, 3)
demo(data, 5)
uj5u.com熱心網友回復:
想象一下,您有一個魔法精靈,可以根據需要為您提供輔助功能。為了使這個函式易于撰寫,您希望做什么?
在我看來,如果我們有一個函式ancestry,它接受一個謂詞來檢查一個節點,并在它匹配時簡單地將整個祖先樹回傳到該節點,那么我們可以這樣寫:
const findAncestryById = (targetId) =>
ancestry (({id}) => id == targetId)
好吧,我們怎么寫ancestry?再一次,在魔法精靈的幫助下,我們可以想象我們有一個函式來遍歷陣列的所有元素,在它們的children節點上重復出現,并提供完整的祖先路徑,然后ancestors可以在此基礎上進行構建。我們可能希望這是一個生成器函式,因為一旦我們找到目標值,它們很容易停止遍歷。所以如果我們想象我們有walk,那么ancestors可能看起來像這樣:
const ancestry = (pred) => (obj) => {
for (let nodes of walk (obj)) {
if (pred (nodes .at (-1))) {
return nodes
}
}
}
所以現在我們需要一個walk函式來遍歷一個陣列及其所有(遞回)后代,在每一步產生到每個節點的完整路徑。好吧,事實證明這是相對簡單的,我們可以像這樣把它們放在一起:
function * walk (xs, path = []) {
for (let x of xs) {
const newPath = path .concat (x)
yield newPath
yield * walk (x .children || [], newPath)
}
}
const ancestry = (pred) => (obj) => {
for (let nodes of walk (obj)) {
if (pred (nodes .at (-1))) {
return nodes
}
}
return []
}
const findAncestryById = (targetId) =>
ancestry (({id}) => id == targetId)
const data = [{id: 1, parent_id: null, title: "First folder", children: [{id: 3, parent_id: 1, title: "First folder in parents", children: []}, {id: 4, parent_id: 1, title: "Second folder in parents", children: [{id: 5, parent_id: 4, title: "test", children: []}]}]}, {id: 2, parent_id: null, title: "Second folder", children: []}]
console .log (findAncestryById (5) (data))
// or to see it without the StackOverflow id-ref pairs:
console .log (JSON .stringify(
findAncestryById (5) (data)
, null, 4))
.as-console-wrapper {max-height: 100% !important; top: 0}
這種魔法精靈風格有一些強大的優勢。它使您可以將特定問題抽象為更通用的問題。通用的通常更容易解決。但即使它們不是,當你完成時,你已經構建了一些適用于許多其他情況的可重用函式。
附注:您的資料似乎有冗余資訊。該parent_id屬性已由樹層次結構編碼。我個人希望將其洗掉,因為總是擔心此類資料不同步。
uj5u.com熱心網友回復:
const data = [{id: 1, parent_id: null, title: "First folder", children: [{id: 3, parent_id: 1, title: "First folder in parents", children: []}, {id: 4, parent_id: 1, title: "Second folder in parents", children: [{id: 5, parent_id: 4, title: "test", children: []}]}]}, {id: 2, parent_id: null, title: "Second folder", children: []}]
function getAllParents(arr, id, res) {
for (const el of arr) {
if (el.id == id) {
res.unshift(el);
return true;
} else {
let is_parent = getAllParents(el.children, id, res);
if (is_parent) {
res.unshift(el);
return true;
}
}
}
}
let res;
for (const i of [1, 2, 3, 4, 5]) {
res = [];
getAllParents(data, i, res);
console.log(
res.map((path) => {
const { id, parent_id, title } = path;
return { id, parent_id, title };
})
);
}
轉載請註明出處,本文鏈接:https://www.uj5u.com/yidong/482189.html
標籤:javascript 数组 循环 递归
