我有這個物件:
var tree = {
name: "Documents",
type: "dir",
full: "/home/adityam/Documents",
children: [
{
name: "file.txt",
type: "file",
full: "/home/adityam/Documents/file.txt",
},
{
name: "anotherFolder",
type: "dir",
full: "/home/adityam/Documents/anotherFolder",
children: [...]
}
]
}
現在,該物件中的元素在每個用戶的計算機上可能都不相同,因為它們是動態生成的。
現在我在這個物件的某處有一個元素,如下所示:
var element = {
name: "anotherFolder",
type: "dir",
full: "/home/adityam/Documents/anotherFolder",
children: [...]
}
我想改變這個元素的屬性“孩子”,我該怎么做?
還有一件事要注意,我擁有的元素總是必然存在于物件中,這意味著該元素不可能不在該物件中。
每個物件都有一個結構:
var tree = {
name: "Some Folder Name",
type: "dir",
full: "full path of the element",
children: [...]
}
如果該屬性type是,dir則該元素將具有一個children屬性,該屬性可能是一個空陣列或包含更多此類元素的陣列。
uj5u.com熱心網友回復:
搜索節點
遞回!
您可以使用遞回(搜索)函式找到此類樹節點的參考:
所有遞回演算法都必須遵守三個重要的定律:
- 遞回演算法必須遞回地呼叫自身。
- 遞回演算法必須有一個基本情況。
- 遞回演算法必須改變它的狀態并朝著基本情況移動。
例如findNodeRecursive(name, node):
- 如果節點的屬性等于
full名稱,則回傳節點。(基本情況:找到) - 如果節點的屬性不是
type,則回傳 null。(基本情況:不能在里面)"dir" - 對于node屬性的每個元素childNode:(轉向一些基本情況)
children- 讓result成為 call 的結果
findNodeRecursive(name, childNode)。(遞回呼叫) - 如果result不為 null,則回傳result。(基本情況:發現于
children)
- 讓result成為 call 的結果
- 回傳空值。(基本情況:未找到)
顯示代碼片段
// Implementation of the algorithm above
function findNodeRecursive(fullName, node) {
if (node.full === fullName) return node;
if (node.type !== "dir") return null;
for (const childNode of node.children) {
const result = findNodeRecursive(fullName, childNode);
if (result !== null) return result;
}
return null;
}
const tree = {
name: "Documents",
type: "dir",
full: "/home/adityam/Documents",
children: [
{
name: "file.txt",
type: "file",
full: "/home/adityam/Documents/file.txt",
},
{
name: "anotherFolder",
type: "dir",
full: "/home/adityam/Documents/anotherFolder",
children: []
}
]
};
console.log(findNodeRecursive("/home/adityam/Documents/anotherFolder", tree));
迭代地
還有一種迭代解決方案,需要將樹展平為一個平面陣列,然后根據節點名稱搜索節點。
展平可以通過多種方式完成,或者再次遞回,或者迭代。
顯示代碼片段
function findNodeIterative(name, node) {
const nodes = [node];
// Iterative flattening
for (let i = 0; i < nodes.length; i) {
if (nodes[i].children) nodes.push(...nodes[i].children);
}
return nodes.find(n => n.full === name);
}
const tree = {
name: "Documents",
type: "dir",
full: "/home/adityam/Documents",
children: [
{
name: "file.txt",
type: "file",
full: "/home/adityam/Documents/file.txt",
},
{
name: "anotherFolder",
type: "dir",
full: "/home/adityam/Documents/anotherFolder",
children: []
}
]
};
console.log(findNodeIterative("/home/adityam/Documents/anotherFolder", tree));
修改children
的值children是一個陣列。如果要修改此陣列,可以使用其中一種變異方法,例如Array.splice()。
顯示代碼片段
// Reference found with some function, for example the above findByName()
const node = {
name: "anotherFolder",
type: "dir",
full: "/home/adityam/Documents/anotherFolder",
children: []
};
const nodesToAdd = [
{
name: "someFile.txt",
type: "file",
full: "/home/adityam/Documents/anotherFolder/someFile.txt"
},
{
name: "someFolder",
type: "dir",
full: "/home/adityam/Documents/anotherFolder/someFolder",
children: []
}
];
console.log("Before modifying:\nNode:", node);
node.children.splice(0, 0, ...nodesToAdd);
console.log("After modifying:\nNode:", node);
.as-console-wrapper{max-height:unset!important;top:0}
uj5u.com熱心網友回復:
解釋中
function recursivelyFindArrayItemByProperties(type, finder) {
const { arrKey, props } = finder;
if (Array.isArray(type)) {
type
// find will exit early.
.find(item =>
!!recursivelyFindArrayItemByProperties(item, finder)
);
} else if (type && ('object' === typeof type)) {
if (
Object
.entries(props)
.every(([key, value]) => type[key] === value)
) {
finder.match = type;
} else {
recursivelyFindArrayItemByProperties(type[arrKey], finder);
}
}
return finder.match;
}
const tree = {
name: "Documents",
type: "dir",
full: "/home/adityam/Documents",
children: [{
name: "file.txt",
type: "file",
full: "/home/adityam/Documents/file.txt",
}, {
name: "anotherFolder",
type: "dir",
full: "/home/adityam/Documents/anotherFolder",
children: [{
name: "fooBar.txt",
type: "file",
full: "/home/adityam/Documents/fooBar.txt",
}, {
name: "bazBiz.txt",
type: "file",
full: "/home/adityam/Documents/bazBiz.txt",
}],
}],
};
console.log(
'found by ... { full: "/home/adityam/Documents/fooBar.txt" } ... ',
recursivelyFindArrayItemByProperties(tree, {
arrKey: 'children',
props: {
full: "/home/adityam/Documents/fooBar.txt",
},
})
);
console.log(
'found by ... { full: "/home/adityam/Documents/bazBiz.txt" } ... ',
recursivelyFindArrayItemByProperties(tree, {
arrKey: 'children',
props: {
full: "/home/adityam/Documents/bazBiz.txt",
},
})
);
console.log(
'\nfound by ... { full: "/home/adityam/Documents/file.txt" } ... ',
recursivelyFindArrayItemByProperties(tree, {
arrKey: 'children',
props: {
full: "/home/adityam/Documents/file.txt",
},
})
);
console.log(
'\nfound by ... { full: "/home/adityam/Documents/anotherFolder" } ... ',
recursivelyFindArrayItemByProperties(tree, {
arrKey: 'children',
props: {
full: "/home/adityam/Documents/anotherFolder",
},
})
);
console.log(
'found by ... { full: "/home/adityam/Documents" } ... ',
recursivelyFindArrayItemByProperties(tree, {
arrKey: 'children',
props: {
full: "/home/adityam/Documents",
},
})
);
console.log(
'\nfound by ... { name: "anotherFolder", type: "dir" } ... ',
recursivelyFindArrayItemByProperties(tree, {
arrKey: 'children',
props: {
name: "anotherFolder",
type: "dir",
// full: "/home/adityam/Documents/anotherFolder",
},
})
);
console.log(
'found by ... { name: "Documents", type: "dir" } ... ',
recursivelyFindArrayItemByProperties(tree, {
arrKey: 'children',
props: {
name: "Documents",
type: "dir",
// full: "/home/adityam/Documents",
},
})
);
.as-console-wrapper { min-height: 100%!important; top: 0; }
uj5u.com熱心網友回復:
正如其他人已經回答的那樣,我將發布我之前寫的答案,但通常在 OP 顯示嘗試之前不會發布。
我認為我們最好將樹導航代碼與檢查我們是否位于正確節點的代碼和修改節點的代碼分開。
由于我不知道您有興趣執行哪種修改,因此我只是notice向物件添加了一個屬性,但是您可以使用任何回傳物件新版本的函式,無論是更改的克隆,還是對變異的參考原始的,或完全不同的東西。這是一個例子:
const modifyNode = (pred, fn) => (node, _, __,
{children = [], ...rest} = node,
kids = children .map (modifyNode (pred, fn))
) => pred (node)
? fn (node)
: {...rest, ...(kids .length ? {children: kids} : {})}
const modifyByPath = (path) => modifyNode (
(node) => node.full === path,
(node) => ({...node, notice: '*** this was modified ***'})
)
var tree = {name: "Documents", type: "dir", full: "/home/adityam/Documents", children: [{name: "file.txt", type: "file", full: "/home/adityam/Documents/file.txt", }, {name: "anotherFolder", type: "dir",full: "/home/adityam/Documents/anotherFolder", children: [/* ... */]}]}
console .log (modifyByPath ('/home/adityam/Documents/anotherFolder') (tree))
.as-console-wrapper {max-height: 100% !important; top: 0}
我們有一個實用函式modifyNode,它接受一個謂詞函式來測驗我們是否命中了正確的節點,還有一個修改函式,它接受一個節點并回傳一個節點,根據需要替換或更改。它回傳一個函式,該函式采用物件陣列遞回配置的節點children(它們本身具有相同的結構),并回傳樹的更改版本,其中每個匹配節點都替換為呼叫修改函式的結果。
我們的主函式 ,modifyByPath接受一個完整的路徑名,并modifyNode使用一個簡單的測驗謂詞和一個虛擬修改函式呼叫,它回傳一個完成我們主要作業的函式。我們會這樣稱呼它modifyByPath (path) (tree)。
轉載請註明出處,本文鏈接:https://www.uj5u.com/caozuo/491475.html
標籤:javascript 目的
上一篇:在動態鍵上設定嵌套動態鍵
