首页 > 解决方案 > 按日期减少对象

问题描述

我有一个这样的数组:

transactionData = [
  { MaterialID: "3000745",
    TransactionQuantity: "2.000",
    TransactionDate: "01/15/2020"
  },
  { MaterialID: "3000745",
    TransactionQuantity: "3.000",
    TransactionDate: "2/24/2020"
  },
  { MaterialID: "3000051",
    TransactionQuantity: "1.000",
    TransactionDate: "3/10/2020"
  },
  { MaterialID: "3000051",
    TransactionQuantity: "1.000",
    TransactionDate: "4/01/2020"
  }
]

像这样的对象:

dateObj = {
  "Jan-20": { sum: 0, count: 0 },
  "Feb-20": { sum: 0, count: 0 },
  "Mar-20": { sum: 0, count: 0 },
  "Apr-20": { sum: 0, count: 0 }
}

我正在尝试减少 transactionData 并返回这样的对象:

{
  "3000051": {
      "monthlyVolume": {
          "Jan-20": {
            "sum": 0,
            "count": 0
          },
          "Feb-20": {
            "sum": 0,
            "count": 0
          },
          "Mar-20": {
            "sum": 1,
            "count": 1
          },
          "Apr-20": {
            "sum": 1,
            "count": 1
          }
      }
  },
  "3000745": {
      "monthlyVolume": {
        "Jan-20": {
            "sum": 2,
            "count": 1
        },
        "Feb-20": {
            "sum": 3,
            "count": 1
        },
        "Mar-20": {
            "sum": 0,
            "count": 0
        },
        "Apr-20": {
            "sum": 0,
            "count": 0
        }
      }
   }
}

出于某种原因,我的 reduce 函数为两个 MaterialID 返回相同的值。我已经为此工作了几个小时,无法弄清楚我做错了什么。我将感谢 SO 社区的任何帮助。

下面是我的代码(注意,我使用的是 dayjs 来格式化)。

 let result = transactionData.reduce((acc, {
    MaterialID, TransactionDate, TransactionQuantity }) => {
    let date = dayjs(TransactionDate).format("MMM-YY");

  const _material = (acc[MaterialID] ?? = { monthlyVolume: dateObj });

  _material.monthlyVolume[date].sum += parseFloat(TransactionQuantity);
  _material.monthlyVolume[date].count++;

    return acc;
  }, {}
)

这也是我尝试的一个代码笔。

代码笔示例

标签: javascriptjavascript-objects

解决方案


1)您使用过

const _material = (acc[MaterialID] ?? = { monthlyVolume: dateObj });

由于中间有空格,这在语法上是不正确的?? =

2)你必须克隆dateObj为每个创建2个单独的对象MaterialID

function createDateObjClone(obj) {
  return Object.keys(obj).reduce((acc, curr) => {
    acc[curr] = { ...obj[curr] };
    return acc;
  }, {});
}

并将其用作

monthlyVolume: { ...createDateObjClone(dateObj) }

您的新运行 CODEPEN 示例

你也可以试试我的解决方案

const transactionData = [
  {
    MaterialID: "3000745",
    TransactionQuantity: "2.000",
    TransactionDate: "01/15/2020",
  },
  {
    MaterialID: "3000745",
    TransactionQuantity: "3.000",
    TransactionDate: "2/24/2020",
  },
  {
    MaterialID: "3000051",
    TransactionQuantity: "1.000",
    TransactionDate: "3/10/2020",
  },
  {
    MaterialID: "3000051",
    TransactionQuantity: "1.000",
    TransactionDate: "4/01/2020",
  },
];

const dateDict = [
  "Jan",
  "Feb",
  "Mar",
  "Apr",
  "May",
  "Jun",
  "Jul",
  "Aug",
  "Sep",
  "Oct",
  "Nov",
  "Dec",
];

const dateObj = {
  "Jan-20": { sum: 0, count: 0 },
  "Feb-20": { sum: 0, count: 0 },
  "Mar-20": { sum: 0, count: 0 },
  "Apr-20": { sum: 0, count: 0 },
};

const getMonthObj = (acc, MaterialID, { month, year }) => acc[MaterialID]["monthlyVolume"][`${dateDict[month - 1]}-${year.slice(-2)}`];

function createDateObjClone(obj) {
  return Object.keys(obj).reduce((acc, curr) => {
    acc[curr] = { ...obj[curr] };
    return acc;
  }, {});
}

function addData(target, sum) {
  target.sum = +sum;
  target.count++;
}

const result = transactionData.reduce((acc, curr) => {
  const { MaterialID, TransactionQuantity, TransactionDate } = curr;
  const [month, , year] = TransactionDate.split("/");

  if (!acc[MaterialID])
    acc[MaterialID] = { monthlyVolume: { ...createDateObjClone(dateObj) } };

  const obj = getMonthObj(acc, MaterialID, { month, year });
  if (obj) addData(obj, TransactionQuantity);

  return acc;
}, {});

console.log(result);
/* This is not a part of answer. It is just to give the output fill height. So IGNORE IT */
.as-console-wrapper { max-height: 100% !important; top: 0; }


推荐阅读