如何使用reduce按名称字符串分配数据

How to assign data by name string using reduce

我有数据数组

像这样减少:

const productMapData = [{
    "occurredAt": "2021-09-20T00:00:00.000",
    "soldTickets": 3836,
    "soldRevenue": 70762,
    "playedOffTickets": 2068,
    "playedOffRevenue": 41429.5,
    "changeInPeriodTickets": 1768,
    "changeInPeriodRevenue": 29332.5,
    "eopAdvanceTickets": 1768,
    "eopAdvanceRevenue": 29332.5,
    "advanceTickets": 1500,
    "advanceRevenue": 11521
  },
  {
    "occurredAt": "2021-09-27T00:00:00.000",
    "soldTickets": 4708,
    "soldRevenue": 88647.5,
    "playedOffTickets": 2127,
    "playedOffRevenue": 49526.5,
    "changeInPeriodTickets": 2581,
    "changeInPeriodRevenue": 39121,
    "eopAdvanceTickets": 2581,
    "eopAdvanceRevenue": 39121,
    "advanceTickets": 700,
    "advanceRevenue": 9521
  },
  {
    "occurredAt": "2021-10-04T00:00:00.000",
    "soldTickets": 5514,
    "soldRevenue": 93969.5,
    "playedOffTickets": 988,
    "playedOffRevenue": 9983,
    "changeInPeriodTickets": 4526,
    "changeInPeriodRevenue": 83986.5,
    "eopAdvanceTickets": 4526,
    "eopAdvanceRevenue": 83986.5,
    "advanceTickets": 1730,
    "advanceRevenue": 14650
  },
  {
    "occurredAt": "2021-10-11T00:00:00.000",
    "soldTickets": 7598,
    "soldRevenue": 109059.5,
    "playedOffTickets": 1476,
    "playedOffRevenue": 16474.5,
    "changeInPeriodTickets": 6122,
    "changeInPeriodRevenue": 92585,
    "eopAdvanceTickets": 6122,
    "eopAdvanceRevenue": 92585,
    "advanceTickets": 800,
    "advanceRevenue": 7560
  },
];

const mapWaterfallChartData = () => productMapData.reduce((previous, point) => {
  const names = ['sopAdvance', 'playedOff', 'sales', 'eopAdvance'];
  const name = names.map(name => name);
  previous[name] = previous[name] || {
    data: [],
    total: 0
  };
  const sopAdvance = point.advanceTickets;
  const playedOff = point.playedOffTickets;
  const sales = point.soldTickets;
  const eopAdvance = point.eopAdvanceTickets;
  return previous;
}, {});

console.log(mapWaterfallChartData(productMapData))

我想要实现的是创建具有 namey 值的新对象,其中名称是名称数组中的值,y 是属于的值那个名字。像这样:

[
  {
    name: 'sopAdvance',
    y: 4730
  },
  {
    name: 'playedOff',
    y: 6659
  },
  {
    name: 'sales',
    y: 21656
  },
  {
    name: 'eopAdvance',
    y: 14997
  }
]

我对如何执行此操作感到困惑和困惑,因此我们将不胜感激。

这可能是我期望的东西

reduce 就好了。我们给出要累积的东西列表,您将获得数组中的每个值和一个总和

请注意,我们可以向存储桶中添加更多键

const productMapData = [{ "occurredAt": "2021-09-20T00:00:00.000", "soldTickets": 3836, "soldRevenue": 70762, "playedOffTickets": 2068, "playedOffRevenue": 41429.5, "changeInPeriodTickets": 1768, "changeInPeriodRevenue": 29332.5, "eopAdvanceTickets": 1768, "eopAdvanceRevenue": 29332.5, "advanceTickets": 1500, "advanceRevenue": 11521 }, { "occurredAt": "2021-09-27T00:00:00.000", "soldTickets": 4708, "soldRevenue": 88647.5, "playedOffTickets": 2127, "playedOffRevenue": 49526.5, "changeInPeriodTickets": 2581, "changeInPeriodRevenue": 39121, "eopAdvanceTickets": 2581, "eopAdvanceRevenue": 39121, "advanceTickets": 700, "advanceRevenue": 9521 }, { "occurredAt": "2021-10-04T00:00:00.000", "soldTickets": 5514, "soldRevenue": 93969.5, "playedOffTickets": 988, "playedOffRevenue": 9983, "changeInPeriodTickets": 4526, "changeInPeriodRevenue": 83986.5, "eopAdvanceTickets": 4526, "eopAdvanceRevenue": 83986.5, "advanceTickets": 1730, "advanceRevenue": 14650 }, { "occurredAt": "2021-10-11T00:00:00.000", "soldTickets": 7598, "soldRevenue": 109059.5, "playedOffTickets": 1476, "playedOffRevenue": 16474.5, "changeInPeriodTickets": 6122, "changeInPeriodRevenue": 92585, "eopAdvanceTickets": 6122, "eopAdvanceRevenue": 92585, "advanceTickets": 800, "advanceRevenue": 7560 }, ];

// you can have more keys going to the same bucket
const buckets = { "advanceTickets": "sopAdvance", "playedOffTickets": "playedOff", "soldTickets" : "sales",               "eopAdvanceTickets":  "eopAdvance" };

const names = Object.keys(buckets);

const mapWaterfallChartData = productMapData.reduce((accumulator, point) => {
  names.forEach(name => {
    const bucket = buckets[name]
    accumulator[bucket] = accumulator[bucket] || {
      data: [],
      total: 0
    };
    accumulator[bucket].data.push(point[name])
    accumulator[bucket].total += point[name]
  })
  return accumulator
}, {});

console.log(mapWaterfallChartData)

没有列表我们可以这样做:

const productMapData = [{ "occurredAt": "2021-09-20T00:00:00.000", "soldTickets": 3836, "soldRevenue": 70762, "playedOffTickets": 2068, "playedOffRevenue": 41429.5, "changeInPeriodTickets": 1768, "changeInPeriodRevenue": 29332.5, "eopAdvanceTickets": 1768, "eopAdvanceRevenue": 29332.5, "advanceTickets": 1500, "advanceRevenue": 11521 }, { "occurredAt": "2021-09-27T00:00:00.000", "soldTickets": 4708, "soldRevenue": 88647.5, "playedOffTickets": 2127, "playedOffRevenue": 49526.5, "changeInPeriodTickets": 2581, "changeInPeriodRevenue": 39121, "eopAdvanceTickets": 2581, "eopAdvanceRevenue": 39121, "advanceTickets": 700, "advanceRevenue": 9521 }, { "occurredAt": "2021-10-04T00:00:00.000", "soldTickets": 5514, "soldRevenue": 93969.5, "playedOffTickets": 988, "playedOffRevenue": 9983, "changeInPeriodTickets": 4526, "changeInPeriodRevenue": 83986.5, "eopAdvanceTickets": 4526, "eopAdvanceRevenue": 83986.5, "advanceTickets": 1730, "advanceRevenue": 14650 }, { "occurredAt": "2021-10-11T00:00:00.000", "soldTickets": 7598, "soldRevenue": 109059.5, "playedOffTickets": 1476, "playedOffRevenue": 16474.5, "changeInPeriodTickets": 6122, "changeInPeriodRevenue": 92585, "eopAdvanceTickets": 6122, "eopAdvanceRevenue": 92585, "advanceTickets": 800, "advanceRevenue": 7560 }, ];


const mapWaterfallChartData = productMapData.reduce((accumulator, point) => {
  Object.keys(point).forEach(name => {
    accumulator[name] = accumulator[name] || {
      data: [],
      total: 0
    };
    accumulator[name].data.push(point[name])
    if (isNaN(point[name])) {
      delete accumulator[name].total; // no need to total the dates
    }
    else {
      accumulator[name].total += point[name]
    }  
  })
  return accumulator
}, {});

console.log(mapWaterfallChartData)

部分问题是您在没有充分理由的情况下陷入了使用 reduce 的陷阱,这可能是您遇到的主要问题。我猜您遇到了错误“无法设置 undefined 的属性。”那是因为你从来没有从你的 reduce 回调中 return previous ,所以下一次传递 previousundefined.

当然可以加上return

    return previous;
}, {});

但坦率地说,使用循环更简单明了。

不过还有一些其他问题。

  • const name = names.map(name => name); 只是复制了 names 数组。
  • Nothing every 将值一起收集到一个对象中。
  • 没有增加总数。

猜测您希望 y 是名称的所有相关 属性 的总和(例如 soldTickets"sopAdvance"),然后它可能看起来像这样(见评论):

const mapWaterfallChartData = (data) => {
    // Creaet the result object with no properties or prorotype (or
    // in modern code, I'd use a `Map` instead)
    const result = Object.create(null);
    // Loop through the points
    for (const point of data) {
        // Loop through the categories
        for (const name of ["sopAdvance", "playedOff", "sales", "eopAdvance"]) {
            // Get the current category entry for this, if we have one
            let entry = result[name];
            if (!entry) {
                // We don't have one yet, create and remember a new one
                entry = result[name] = {
                    name,
                    y: 0,
                };
            }
            // Update `y` with the relevant measure
            switch (name) {
                case "sopAdvance";
                    entry.y += point.advanceTickets;
                    break;
                case "playedOff";
                    entry.y += point.playedOffTickets;
                    break;
                case "sales";
                    entry.y += point.soldTickets;
                    break;
                case "eopAdvance";
                    entry.y += point.eopAdvanceTickets;
                    break;
            }
        }
    }
    return Object.values(result);
};

但是在类别数组中包含 属性 名称可能会很方便,因此我们不需要 switch:

const categories = [
    {name: "sopAdvance", prop: "advanceTickets"},
    {name: "playedOff", prop: "playedOffTickets"},
    {name: "sales", prop: "soldTickets"},
    {name: "eopAdvance", prop: "eopAdvanceTickets"},
];
const mapWaterfallChartData = (data) => {
    // Creaet the result object with no properties or prorotype (or
    // in modern code, I'd use a `Map` instead)
    const result = Object.create(null);
    // Loop through the points
    for (const point of data) {
        // Loop through the categories
        for (const {name, prop} of categories) {
            // Get the current category entry for this, if we have one
            let entry = result[name];
            if (!entry) {
                // We don't have one yet, create and remember a new one
                entry = result[name] = {
                    name,
                    y:0,
                };
            }
            // Update `y` with the relevant measure
            entry.y += point[prop];
        }
    }
    return Object.values(result);
};

实例:

const productMapData = [{
    "occurredAt": "2021-09-20T00:00:00.000",
    "soldTickets": 3836,
    "soldRevenue": 70762,
    "playedOffTickets": 2068,
    "playedOffRevenue": 41429.5,
    "changeInPeriodTickets": 1768,
    "changeInPeriodRevenue": 29332.5,
    "eopAdvanceTickets": 1768,
    "eopAdvanceRevenue": 29332.5,
    "advanceTickets": 1500,
    "advanceRevenue": 11521
  },
  {
    "occurredAt": "2021-09-27T00:00:00.000",
    "soldTickets": 4708,
    "soldRevenue": 88647.5,
    "playedOffTickets": 2127,
    "playedOffRevenue": 49526.5,
    "changeInPeriodTickets": 2581,
    "changeInPeriodRevenue": 39121,
    "eopAdvanceTickets": 2581,
    "eopAdvanceRevenue": 39121,
    "advanceTickets": 700,
    "advanceRevenue": 9521
  },
  {
    "occurredAt": "2021-10-04T00:00:00.000",
    "soldTickets": 5514,
    "soldRevenue": 93969.5,
    "playedOffTickets": 988,
    "playedOffRevenue": 9983,
    "changeInPeriodTickets": 4526,
    "changeInPeriodRevenue": 83986.5,
    "eopAdvanceTickets": 4526,
    "eopAdvanceRevenue": 83986.5,
    "advanceTickets": 1730,
    "advanceRevenue": 14650
  },
  {
    "occurredAt": "2021-10-11T00:00:00.000",
    "soldTickets": 7598,
    "soldRevenue": 109059.5,
    "playedOffTickets": 1476,
    "playedOffRevenue": 16474.5,
    "changeInPeriodTickets": 6122,
    "changeInPeriodRevenue": 92585,
    "eopAdvanceTickets": 6122,
    "eopAdvanceRevenue": 92585,
    "advanceTickets": 800,
    "advanceRevenue": 7560
  },
];

const categories = [
    {name: "sopAdvance", prop: "advanceTickets"},
    {name: "playedOff", prop: "playedOffTickets"},
    {name: "sales", prop: "soldTickets"},
    {name: "eopAdvance", prop: "eopAdvanceTickets"},
];
const mapWaterfallChartData = (data) => {
    // Creaet the result object with no properties or prorotype (or
    // in modern code, I'd use a `Map` instead)
    const result = Object.create(null);
    // Loop through the points
    for (const point of data) {
        // Loop through the categories
        for (const {name, prop} of categories) {
            // Get the current category entry for this, if we have one
            let entry = result[name];
            if (!entry) {
                // We don't have one yet, create and remember a new one
                entry = result[name] = {
                    name,
                    y:0,
                };
            }
            // Update `y` with the relevant measure
            entry.y += point[prop];
        }
    }
    return Object.values(result);
};

console.log(mapWaterfallChartData(productMapData));