我有一組物件,它們代表類似于系統硬碟檔案夾結構的東西。資料以嵌套的物件陣串列示。每個物件都是一個包含一些檔案和檔案夾的檔案夾。我確切地知道直接放置在每個節點中的檔案大小的總和。但我不知道包含其子節點的節點占用了多少空間。
以下是資料示例:
[{
id: 1,
name: 'root',
filesSize: 123456,
children: [{
id: 2,
name: 'child 1',
filesSize: 789654,
},
{
id: 3,
name: 'child 2',
filesSize: 321123,
children: [{
id: 4,
name: 'child 3 - 1',
filesSize: 88888,
},
{
id: 5,
name: 'child 3 - 2',
filesSize: 99999,
children: [{
id: 99999,
name: 'child m - n',
filesSize: ...,
},
.
.
.
}]
}]
}]
我嘗試使用Array.reduce,但它對我沒有幫助,因為它只迭代物件的直接子級 - 而不是嵌套陣列的n級。像這樣的東西:
const parentSize = typeof parent['total'] !== 'undefined' ? parent['total'] : parent.filesSize;
parent['total'] = children.reduce((sum, child) => {
return sum (typeof child.total !== 'undefined' ? child.filesSize : child.total);
}, parentSize);
我錯過了什么?
uj5u.com熱心網友回復:
只是一個說明:
假設您的大小單位是位元組:
1PB是1_000_000_000_000_000位元組(或1e3 ** 5):因此您的總和(即 JSnumber)可以安全地持有Number.MAX_SAFE_INTEGER / (1e3 ** 5),大約為9. 如果您預計您的大小將接近 9 PB,則應使用BigInt型別來存盤總和,而不是使用number.
其他答案演示了遞回方法,它們簡潔而優雅,但如果您的層次結構太多(堆疊溢位!),則會失敗。
這是一個迭代的替代方案:
TS游樂場
function getTotal (containerNode) {
let total = 0;
const stack = [containerNode];
while (stack.length > 0) {
const node = stack.pop();
// Already available, skip children
if (typeof node.total === 'number') {
total = node.total;
continue;
}
total = node.filesSize;
if (!node.children?.length) continue;
for (const child of node.children) stack.push(child);
}
return total;
}
// Example usage:
const nodes = [
{
id: 1,
name: 'root',
filesSize: 123456,
children: [
{
id: 2,
name: 'child 1',
filesSize: 789654,
},
{
id: 3,
name: 'child 2',
filesSize: 321123,
total: 321123 88888 99999 34523,
children: [
{
id: 4,
name: 'child 3 - 1',
filesSize: 88888,
},
{
id: 5,
name: 'child 3 - 2',
filesSize: 99999,
children: [
{
id: 99999,
name: 'child m - n',
filesSize: 34523,
},
// ...
],
},
],
},
],
},
];
function test (containerNode, expectedTotal) {
const actual = getTotal(containerNode);
return `${containerNode.id}: ${actual === expectedTotal ? 'pass' : 'fail'}`;
}
const results = [
test(
nodes[0].children[1].children[1].children[0],
34523,
),
test(
nodes[0].children[1].children[1],
99999 34523,
),
test(
nodes[0].children[1].children[0],
88888,
),
test(
nodes[0].children[1],
321123 88888 99999 34523,
),
test(
nodes[0].children[0],
789654,
),
test(
nodes[0],
123456 789654 321123 88888 99999 34523,
),
];
for (const result of results) console.log(result);
uj5u.com熱心網友回復:
我冒昧地將物件從上到下翻了一番,所以它在根處分裂了四層深。
/**@function
* @Name totalFileSize
* @Description - This function accepts array of objects and any nested array of
* objects as well. It will extract a number value<sup>?</sup> of a given key
* and recursively search all sub-arrays as well. It will return the sum of all
* extarcted values.
* @param {array<object>} objArr - An array of objects
* @param {string} prop - A key/property with a number value
* @returns {number} - A sum of all extracted number values
*/
傳遞物件陣列和要獲取總和的屬性。
// data↘? ↙?"filesSize"
const totalFileSize = (objArr, prop) =>
接下來,運行每個物件.map(),然后通過使用將每個物件轉換為對陣列Object.entries()。對陣列是一個二維陣列,其中子陣列由兩個元素組成:
[[key, value], [key, value],...]
objArr.map(obj => Object.entries(obj)
// [{A: 1, B: 'z'}, {...},...] => [["A", 1], ["B", "z"], [...],...]
現在我們有了一個二維陣列,使用陣列方法更容易使用。方法的邏輯選擇是.reduce()因為我們需要一個結果。第二個引數表示當前迭代的元素,注意它被解構為一個陣列(特別是鍵/值對)。在這種形式下,我們可以很容易地構造更細粒度的運算式。
// ↙?On each iteration, this value accumulates when a match is made
.reduce((sum, [key, val]) =>
// property↗? ↖?value
解構后的值讓我們可以寫出更簡潔直接的方式。這個函式的核心是if/else if/else一個三元條件陳述句。
/* if the current key matches prop ("filesSize"), then add sum and the current value
(val).*/
key == prop ? sum parseInt(val) :
/* Note: the value needed to be coverted to a number because the operator coerced
it into a String.*/
現在進入else if三元運算子的第二個(或)。我注意到其他答案中有一個正在運行的總 ptoperty,所??以這里是獲取它的地方obj.total = sum parseInt(totalFileSize(val, prop)):它sum是每個遞回呼叫的和回傳值。我認為不應該為每個物件計算總數(你得到的只是 的重復值filesSize)。
/* else if val is an array recursively invoke totalFileSize() and pass val and
prop in...*/
Array.isArray(val) ? obj.total = sum parseInt(totalFileSize(val, prop)) :
// ...then convert it's return into a number and add it to sum
否則加 0 到總和。不再擔心任何不匹配的值。
0, 0))
// The last zero is the initial value of `.reduce()`
最后要做的是清理回傳值。資料翻了一番,因此我可以演示處理多個分支的功能。此時,所有數字"filesSize"現在都是陣列中的兩個總數。最后一步將所有分支添加在一起。
.reduce((total, current) => total current);
const data =[{"id":1,"name":"root","filesSize":123456,"children":[{"id":2,"name":"child 1","filesSize":789654},{"id":3,"name":"child 2","filesSize":321123,"children":[{"id":4,"name":"child 3 - 1","filesSize":88888},{"id":5,"name":"child 3 - 2","filesSize":99999,"children":[{"id":6,"name":"child 4 - 1","filesSize":325941}]}]}]},
{"id":7,"name":"root","filesSize":654321,"children":[{"id":8,"name":"child 1","filesSize":978855},{"id":9,"name":"child 2","filesSize":123321,"children":[{"id":10,"name":"child 3 - 1","filesSize":11111},{"id":11,"name":"child 3 - 2","filesSize":66666,"children":[{"id":12,"name":"child 4 - 1","filesSize":18756}]}]}]}];
const totalFileSize = (objArr, prop) =>
objArr.map(obj => Object.entries(obj)
.reduce((sum, [key, val]) =>
key == prop ? sum parseInt(val) :
Array.isArray(val) ? obj.total = sum parseInt(totalFileSize(val, prop)) :
0, 0))
.reduce((total, current) => total current);
console.log(`Input array is doubled at the root so this the total sum of 12 objects not 6 like OP example.`);
console.log(totalFileSize(data, "filesSize"));
console.log(data);
uj5u.com熱心網友回復:
const data = [{
id: 1,
name: 'root',
filesSize: 123456,
children: [{
id: 2,
name: 'child 1',
filesSize: 789654,
},
{
id: 3,
name: 'child 2',
filesSize: 321123,
children: [{
id: 4,
name: 'child 3 - 1',
filesSize: 88888,
},
{
id: 5,
name: 'child 3 - 2',
filesSize: 99999,
children: [{
id: 99999,
name: 'child m - n',
filesSize: 12345,
}]
}]
}]
}];
function calculateTotals(d) {
let total = d.filesSize;
if (d.children)
d.children.forEach(c => total = calculateTotals(c));
return d.total = total;
}
data.forEach(d => calculateTotals(d));
console.log(data);
uj5u.com熱心網友回復:
使用reduce很好,但你需要:
- 遞回,以便
reduce在需要時也呼叫子級。 - 總是分配給
total. 檢查它是否已經存在是沒有用的,因為它不會。如果確實如此,那么依賴它是有風險的,因為您不知道在添加該屬性后樹是否已被修改。
let tree = [{id: 1,name: 'root',filesSize: 123456,children: [{id: 2,name: 'child 1',filesSize: 789654,}, {id: 3,name: 'child 2',filesSize: 321123,children: [{id: 4,name: 'child 3 - 1',filesSize: 88888,}, {id: 5,name: 'child 3 - 2',filesSize: 99999,children: [{id: 99999,name: 'child m - n',filesSize: 1234}]}]}]}];
let totalSize = tree.reduce(function recur(sum, child) {
return sum (child.total = (child.children ?? []).reduce(recur, child.filesSize));
}, 0);
// The returned size can be interesting when the top level has
// multiple entries (which is not the case in your example):
console.log(totalSize);
console.log(tree);
轉載請註明出處,本文鏈接:https://www.uj5u.com/gongcheng/443240.html
標籤:javascript 数组 嵌套列表
