主頁 > 軟體工程 > 獲取具有無限深度的嵌套物件陣列的屬性總和

獲取具有無限深度的嵌套物件陣列的屬性總和

2022-03-14 19:31:37 軟體工程

我有一組物件,它們代表類似于系統硬碟檔案夾結構的東西。資料以嵌套的物件陣串列示。每個物件都是一個包含一些檔案和檔案夾的檔案夾。我確切地知道直接放置在每個節點中的檔案大小的總和。但我不知道包含其子節點的節點占用了多少空間。

以下是資料示例:

[{
    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熱心網友回復:

只是一個說明:

假設您的大小單位是位元組:

1 PB1_000_000_000_000_000位元組(或1e3 ** 5):因此您的總和(即 JS number)可以安全地持有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 数组 嵌套列表

上一篇:正在開發一個名為DieToss的程式,該程式會搜索重復的投擲。如何限制括號可以關閉的位置?

下一篇:為Postman/GET請求的可能json輸出格式化物件陣列

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • Git本地庫既關聯GitHub又關聯Gitee

    創建代碼倉庫 使用gitee舉例(github和gitee差不多) 1.在gitee右上角點擊+,選擇新建倉庫 ? 2.選擇填寫倉庫資訊,然后進行創建 ? 3.服務端已經準備好了,本地開始作準備 (1)Git 全域設定 git config --global user.name "成鈺" git c ......

    uj5u.com 2020-09-10 05:04:14 more
  • CODING DevOps 代碼質量實戰系列第二課,相約周三

    隨著 ToB(企業服務)的興起和 ToC(消費互聯網)產品進入成熟期,線上故障帶來的損失越來越大,代碼質量越來越重要,而「質量內建」正是 DevOps 核心理念之一。**《DevOps 代碼質量實戰(PHP 版)》**為 CODING DevOps 代碼質量實戰系列的第二課,同時也是本系列的 PHP ......

    uj5u.com 2020-09-10 05:07:43 more
  • 推薦Scrum書籍

    推薦Scrum書籍 直接上干貨,推薦書籍清單如下(推薦有順序的哦) Scrum指南 Scrum精髓 Scrum敏捷軟體開發 Scrum捷徑 硝煙中的Scrum和XP : 我們如何實施Scrum 敏捷軟體開發:Scrum實戰指南 Scrum要素 大規模Scrum:大規模敏捷組織的設計 用戶故事地圖 用 ......

    uj5u.com 2020-09-10 05:07:45 more
  • CODING DevOps 代碼質量實戰系列最后一課,周四發車

    隨著 ToB(企業服務)的興起和 ToC(消費互聯網)產品進入成熟期,線上故障帶來的損失越來越大,代碼質量越來越重要,而「質量內建」正是 DevOps 核心理念之一。 **《DevOps 代碼質量實戰(Java 版)》**為 CODING DevOps 代碼質量實戰系列的最后一課,同時也是本系列的 ......

    uj5u.com 2020-09-10 05:07:52 more
  • 敏捷軟體工程實踐書籍

    Scrum轉型想要做好,第一步先了解并真正落實Scrum,那么我推薦的Scrum書籍是要看懂并實踐的。第二步是團隊的工程實踐要做扎實。 下面推薦工程實踐書單: 重構:改善既有代碼的設計 決議極限編程 : 擁抱變化 代碼整潔代碼 程式員的職業素養 修改代碼的藝術 撰寫可讀代碼的藝術 測驗驅動開發 : ......

    uj5u.com 2020-09-10 05:07:55 more
  • Jenkins+svn+nginx實作windows環境自動部署vue前端專案

    前面文章介紹了Jenkins+svn+tomcat實作自動化部署,現在終于有空抽時間出來寫下Jenkins+svn+nginx實作自動部署vue前端專案。 jenkins的安裝和配置已經在前面文章進行介紹,下面介紹實作vue前端專案需要進行的哪些額外的步驟。 注意:在安裝jenkins和nginx的 ......

    uj5u.com 2020-09-10 05:08:49 more
  • CODING DevOps 微服務專案實戰系列第一課,明天等你

    CODING DevOps 微服務專案實戰系列第一課**《DevOps 微服務專案實戰:DevOps 初體驗》**將由 CODING DevOps 開發工程師 王寬老師 向大家介紹 DevOps 的基本理念,并探討為什么現代開發活動需要 DevOps,同時將以 eShopOnContainers 項 ......

    uj5u.com 2020-09-10 05:09:14 more
  • CODING DevOps 微服務專案實戰系列第二課來啦!

    近年來,工程專案的結構越來越復雜,需要接入合適的持續集成流水線形式,才能滿足更多變的需求,那么如何優雅地使用 CI 能力提升生產效率呢?CODING DevOps 微服務專案實戰系列第二課 《DevOps 微服務專案實戰:CI 進階用法》 將由 CODING DevOps 全堆疊工程師 何晨哲老師 向 ......

    uj5u.com 2020-09-10 05:09:33 more
  • CODING DevOps 微服務專案實戰系列最后一課,周四開講!

    隨著軟體工程越來越復雜化,如何在 Kubernetes 集群進行灰度發布成為了生產部署的”必修課“,而如何實作安全可控、自動化的灰度發布也成為了持續部署重點關注的問題。CODING DevOps 微服務專案實戰系列最后一課:**《DevOps 微服務專案實戰:基于 Nginx-ingress 的自動 ......

    uj5u.com 2020-09-10 05:10:00 more
  • CODING 儀表盤功能正式推出,實作作業資料可視化!

    CODING 儀表盤功能現已正式推出!該功能旨在用一張張統計卡片的形式,統計并展示使用 CODING 中所產生的資料。這意味著無需額外的設定,就可以收集歸納寶貴的作業資料并予之量化分析。這些海量的資料皆會以圖表或串列的方式躍然紙上,方便團隊成員隨時查看各專案的進度、狀態和指標,云端協作迎來真正意義上 ......

    uj5u.com 2020-09-10 05:11:01 more
最新发布
  • windows系統git使用ssh方式和gitee/github進行同步

    使用git來clone專案有兩種方式:HTTPS和SSH:
    HTTPS:不管是誰,拿到url隨便clone,但是在push的時候需要驗證用戶名和密碼;
    SSH:clone的專案你必須是擁有者或者管理員,而且需要在clone前添加SSH Key。SSH 在push的時候,是不需要輸入用戶名的,如果配置... ......

    uj5u.com 2023-04-19 08:41:12 more
  • windows系統git使用ssh方式和gitee/github進行同步

    使用git來clone專案有兩種方式:HTTPS和SSH:
    HTTPS:不管是誰,拿到url隨便clone,但是在push的時候需要驗證用戶名和密碼;
    SSH:clone的專案你必須是擁有者或者管理員,而且需要在clone前添加SSH Key。SSH 在push的時候,是不需要輸入用戶名的,如果配置... ......

    uj5u.com 2023-04-19 08:35:34 more
  • 2023年農牧行業6大CRM系統、5大場景盤點

    在物聯網、大資料、云計算、人工智能、自動化技術等現代資訊技術蓬勃發展與逐步成熟的背景下,數字化正成為農牧行業供給側結構性變革與高質量發展的核心驅動因素。因此,改造和提升傳統農牧業、開拓創新現代智慧農牧業,加快推進農牧業的現代化、資訊化、數字化建設已成為農牧業發展的重要方向。 當下,企業數字化轉型已經 ......

    uj5u.com 2023-04-18 08:05:44 more
  • 2023年農牧行業6大CRM系統、5大場景盤點

    在物聯網、大資料、云計算、人工智能、自動化技術等現代資訊技術蓬勃發展與逐步成熟的背景下,數字化正成為農牧行業供給側結構性變革與高質量發展的核心驅動因素。因此,改造和提升傳統農牧業、開拓創新現代智慧農牧業,加快推進農牧業的現代化、資訊化、數字化建設已成為農牧業發展的重要方向。 當下,企業數字化轉型已經 ......

    uj5u.com 2023-04-18 08:00:18 more
  • 計算機組成原理—存盤器

    計算機組成原理—硬體結構 二、存盤器 1.概述 存盤器是計算機系統中的記憶設備,用來存放程式和資料 1.1存盤器的層次結構 快取-主存層次主要解決CPU和主存速度不匹配的問題,速度接近快取 主存-輔存層次主要解決存盤系統的容量問題,容量接近與價位接近于主存 2.主存盤器 2.1概述 主存與CPU的聯 ......

    uj5u.com 2023-04-17 08:20:31 more
  • 談一談我對協同開發的一些認識

    如今各互聯網公司普通都使用敏捷開發,采用小步快跑的形式來進行專案開發。如果是小專案或者小需求,那一個開發可能就搞定了。但對于電商等復雜的系統,其功能多,結構復雜,一個人肯定是搞不定的,所以都是很多人來共同開發維護。以我曾經待過的商城團隊為例,光是后端開發就有七十多人。 為了更好地開發這類大型系統,往 ......

    uj5u.com 2023-04-17 08:18:55 more
  • 專案管理PRINCE2核心知識點整理

    PRINCE2,即 PRoject IN Controlled Environment(受控環境中的專案)是一種結構化的專案管理方法論,由英國政府內閣商務部(OGC)推出,是英國專案管理標準。
    PRINCE2 作為一種開放的方法論,是一套結構化的專案管理流程,描述了如何以一種邏輯性的、有組織的方法,... ......

    uj5u.com 2023-04-17 08:18:51 more
  • 談一談我對協同開發的一些認識

    如今各互聯網公司普通都使用敏捷開發,采用小步快跑的形式來進行專案開發。如果是小專案或者小需求,那一個開發可能就搞定了。但對于電商等復雜的系統,其功能多,結構復雜,一個人肯定是搞不定的,所以都是很多人來共同開發維護。以我曾經待過的商城團隊為例,光是后端開發就有七十多人。 為了更好地開發這類大型系統,往 ......

    uj5u.com 2023-04-17 08:18:00 more
  • 專案管理PRINCE2核心知識點整理

    PRINCE2,即 PRoject IN Controlled Environment(受控環境中的專案)是一種結構化的專案管理方法論,由英國政府內閣商務部(OGC)推出,是英國專案管理標準。
    PRINCE2 作為一種開放的方法論,是一套結構化的專案管理流程,描述了如何以一種邏輯性的、有組織的方法,... ......

    uj5u.com 2023-04-17 08:17:55 more
  • 計算機組成原理—存盤器

    計算機組成原理—硬體結構 二、存盤器 1.概述 存盤器是計算機系統中的記憶設備,用來存放程式和資料 1.1存盤器的層次結構 快取-主存層次主要解決CPU和主存速度不匹配的問題,速度接近快取 主存-輔存層次主要解決存盤系統的容量問題,容量接近與價位接近于主存 2.主存盤器 2.1概述 主存與CPU的聯 ......

    uj5u.com 2023-04-17 08:12:06 more