首页 > 解决方案 > 将总和添加到对象中的每个元素并返回 Javascript 中的前 N ​​个键/值对

问题描述

我有一个键/值对的对象数组,其中值是另一组键/值对,其中所有值都是数字。我想总结每个键的所有值,然后为每个键添加一个具有聚合总和的新元素。一旦我有了它,我希望能够根据聚合的总和值选择对象数组中的前 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 个项目,以便我可以遍历它们并为每个项目创建一个 d3 可视化前n项。我唯一的问题是获得最重要的项目所需的最终数组。

编辑:我能够编写一个嵌套循环来添加一个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;
}

标签: javascriptarraysobjectd3.js

解决方案


由于对象数据结构,不可能像这样对值进行排序。但是,我能够将条目数限制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);


推荐阅读