【问题标题】:Adding sum to each element in an object and return top N key/value pairs in Javascript将总和添加到对象中的每个元素并返回 Javascript 中的前 N ​​个键/值对
【发布时间】:2021-01-29 09:25:37
【问题描述】:

我有一个键/值对对象数组,其中值是另一组键/值对,其中所有值都是数字。我想总结每个键的所有值,然后为每个键添加一个具有聚合总和的新元素。一旦我有了它,我希望能够根据聚合的总和值选择对象数组中的前 5 个主键。

我的数据(对象)如下所示

{
   "Napkins":{
      "N/A":200,
      "No supply":100,
      "More than 1 wk":150,
      "1 week or less":50
   },
   "Plates":{
      "N/A":800
   },
   "Forks":{
      "N/A":100,
      "No supply":100,
      "More than 1 wk":50,
      "1 week or less":50
   },
   "Knives":{
      "N/A":300,
      "No supply":100
   }
}

我希望能够添加一个 total 值来对每个主外键的值求和,以便我的最终对象看起来像这样:

{
   "Napkins":{
      "N/A":200,
      "No supply":100,
      "More than 1 wk":150,
      "1 week or less":50,
      "total":500
   },
   "Plates":{
      "N/A":800,
      "total":800
   },
   "Forks":{
      "N/A":100,
      "No supply":100,
      "More than 1 wk":50,
      "1 week or less":50,
      "total":300
   },
   "Knives":{
      "N/A":300,
      "No supply":100,
      "total":400
   }
}

一旦我有了它,我希望能够轻松地按total 对数组进行排序,并将其按前 5 或任意数字 n 切片,只返回那些 n 个项目,以便我可以遍历它们并为每个顶部 n 个项目创建一个 d3 可视化。我唯一的问题是获得顶级项目所需的最终数组。

编辑:我能够编写一个嵌套循环来添加一个total 字段。不确定是否有更好的方法来做到这一点,但现在希望了解访问切片和访问具有前 5 个 total 值的键/值元素的最佳方法。这是我用于循环原始对象的代码:

for (const item of Object.values(processed_data)){
    let sum = Object.values(item).reduce((a,b) => a+b, 0);
    item.total = sum;
}

【问题讨论】:

    标签: javascript arrays object d3.js


    【解决方案1】:

    由于对象数据结构的原因,无法对这些值进行排序。但是,我能够在下面的代码中将条目数限制为N

    const data = {
      "Napkins": {
        "N/A": 200,
        "No supply": 100,
        "More than 1 wk": 150,
        "1 week or less": 50
      },
      "Plates": {
        "N/A": 800
      },
      "Forks": {
        "N/A": 100,
        "No supply": 100,
        "More than 1 wk": 50,
        "1 week or less": 50
      },
      "Knives": {
        "N/A": 300,
        "No supply": 100
      }
    };
    
    const getTopN = 3;
    Object.values(data).forEach(reasons => {
      // Alternatively, d3.sum(Object.values(reasons)) also works
      reasons.total = Object.values(reasons).reduce((sum, v) => sum + v, 0);
    }, {});
    
    // Get the value from the N^th threshold
    const threshold = Object.values(data)
      .map(reasons => reasons.total)
      .sort()
      .reverse()[getTopN - 1];
    
    const topN = Object.entries(data)
      .filter(([type, reasons]) => reasons.total >= threshold)
      .reduce((obj, [type, reasons]) => {
        obj[type] = reasons;
        return obj;
      }, {});
    
    console.log(topN);

    或者,你能改变数据结构吗:

    const data = {
      "Napkins": {
        "N/A": 200,
        "No supply": 100,
        "More than 1 wk": 150,
        "1 week or less": 50
      },
      "Plates": {
        "N/A": 800
      },
      "Forks": {
        "N/A": 100,
        "No supply": 100,
        "More than 1 wk": 50,
        "1 week or less": 50
      },
      "Knives": {
        "N/A": 300,
        "No supply": 100
      }
    };
    
    const getTopN = 3;
    const arrayData = Object.entries(data)
      .map(([item, reasons]) => ({
        item,
        total: Object.values(reasons).reduce((sum, v) => sum + v, 0),
        reasons
      }))
      .sort((a, b) => b.total - a.total)
      .slice(0, getTopN);
    console.log(arrayData);

    【讨论】:

    • 谢谢!这行得通。但是 - 当我尝试使用必须在 d3 中可视化它的代码时,我现在遇到了问题,因为我似乎无法在正确的数据结构中得到它。另一种方法是更改​​我的可视化代码以使用上面的输出,但更改数据似乎更容易。有没有一种方法可以轻松地将上面的数据转换为arrayData 中每个项目的以下数组形式:0: {reason: "N/A", value:200} 1: {reason: "No supply", value:100} 2: {reason: "More than 1 wk", value: 150} 3: {reason: "1 week or less", value: 50} 4: {reason: "total", value: 500 }
    猜你喜欢
    • 2014-04-14
    • 1970-01-01
    • 1970-01-01
    • 2020-07-21
    • 1970-01-01
    • 2022-07-01
    • 2018-09-14
    • 1970-01-01
    • 2016-02-11
    相关资源
    最近更新 更多