You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

JS中如何按条件为科目成绩数据添加含值对象数组?

科目成绩数据结构化解决方案

问题描述

我有一个包含学生科目成绩的对象,需要按键名进行数据结构化:每个科目分为第1部分(part_1)和第2部分(part_2),每部分需包含MCQ、CQ、total字段(部分科目没有MCQ,比如English)。目前卡在怎么给各科目部分添加对应值到对象数组里,现有代码生成不了预期输出,具体代码和预期输出如下:

现有代码

const result = {
  id: 427,
  merit: "1",
  name: "Israt Jahan",
  group_name: "business",
  GPA: "4.4",
  english_1st_CQ: "24",
  english_1st_total: "24",
  english_2nd_CQ: "24",
  english_2nd_total: "24",
  english_GP: "2",
  english_percentage: "48",
  english_total: "48",
  production_1st_CQ: "32",
  production_1st_MCQ: "11",
  production_1st_total: "43",
  production_2nd_CQ: "26",
  production_2nd_MCQ: "11",
  production_2nd_total: "37",
  production_GP: "5",
  production_percentage: "80",
  roll: 1401,
  total_failed: "0",
  total_gp: "24",
  total_marks: "439",
};

const subjectAdd = (arr, title) => {
  const node = arr.find((node) => node.subject === title) ?? {
    subject: title.split(" ")[0],
    part_1: [],
    part_2: [],
  };
  if (arr.every((e) => e.subject !== node.subject)) arr.push(node);
  return node;
};

const subjects = (data) => {
  const subject = [];
  Object.entries(data).map(([key, value]) => {
    const [subjectName, subjectPosition, suffix] = key.split("_");
    if (
      subjectName != "id" &&
      subjectName != "date" &&
      subjectName != "group" &&
      subjectName != "roll" &&
      subjectName != "name" &&
      subjectName != "merit" &&
      subjectName != "GPA" &&
      subjectName != "total"
    ) {
      const newSubject = subjectAdd(subject, `${subjectName}  ${subjectPosition}`);
      const part1 = subjectAdd(newSubject.part_1, `${subjectName}  ${subjectPosition}`);
      const part2 = subjectAdd(newSubject.part_2, `${subjectName}  ${subjectPosition}`);
    }
  });

  return subject;
};
console.log("result", subjects(result));

预期输出

[
  {
    "subject": "english",
    "part_1": [
      {
        "subject": "english 1st",
        "CQ": 24,
        "total": 24
      }
    ],
    "part_2": [
      {
        "subject": "english 2nd",
        "CQ": 24,
        "total": 24
      }
    ]
  },
  {
    "subject": "production",
    "part_1": [
      {
        "subject": "production 1st",
        "MCQ": 11,
        "CQ": 32,
        "total": 43
      }
    ],
    "part_2": [
      {
        "subject": "production 2nd",
        "MCQ": 11,
        "CQ": 26,
        "total": 37
      }
    ]
  }
]

解决方法

原代码的核心问题在于subjectAdd函数职责混淆,以及未正确将字段值映射到对应科目部分的属性中。以下是修正后的代码:

const result = {
  id: 427,
  merit: "1",
  name: "Israt Jahan",
  group_name: "business",
  GPA: "4.4",
  english_1st_CQ: "24",
  english_1st_total: "24",
  english_2nd_CQ: "24",
  english_2nd_total: "24",
  english_GP: "2",
  english_percentage: "48",
  english_total: "48",
  production_1st_CQ: "32",
  production_1st_MCQ: "11",
  production_1st_total: "43",
  production_2nd_CQ: "26",
  production_2nd_MCQ: "11",
  production_2nd_total: "37",
  production_GP: "5",
  production_percentage: "80",
  roll: 1401,
  total_failed: "0",
  total_gp: "24",
  total_marks: "439",
};

// 获取或创建科目对象
const getOrCreateSubject = (subjects, subjectName) => {
  let subject = subjects.find(s => s.subject === subjectName);
  if (!subject) {
    subject = {
      subject: subjectName,
      part_1: [],
      part_2: []
    };
    subjects.push(subject);
  }
  return subject;
};

// 获取或创建科目下的部分条目(1st/2nd)
const getOrCreatePartItem = (part, subjectFullName) => {
  let item = part.find(i => i.subject === subjectFullName);
  if (!item) {
    item = { subject: subjectFullName };
    part.push(item);
  }
  return item;
};

const subjects = (data) => {
  const subjectList = [];
  // 定义需要忽略的非科目字段
  const ignoreFields = new Set(['id', 'merit', 'name', 'group_name', 'GPA', 'roll', 'total_failed', 'total_gp', 'total_marks']);
  
  Object.entries(data).forEach(([key, value]) => {
    const parts = key.split("_");
    // 只处理符合 科目_部分_类型 格式的字段
    if (parts.length === 3 && !ignoreFields.has(parts[0])) {
      const [subjectName, partSuffix, field] = parts;
      const subjectFullName = `${subjectName} ${partSuffix}`;
      const subject = getOrCreateSubject(subjectList, subjectName);
      
      // 判断是part_1还是part_2
      const targetPart = partSuffix === '1st' ? subject.part_1 : subject.part_2;
      const partItem = getOrCreatePartItem(targetPart, subjectFullName);
      
      // 将值转为数字,赋值到对应字段
      partItem[field.toUpperCase()] = parseInt(value, 10);
    }
  });
  
  return subjectList;
};

console.log(JSON.stringify(subjects(result), null, 2));

关键改进点

  • 拆分职责:把获取科目对象和科目部分条目的逻辑拆成独立函数,避免逻辑混乱
  • 精准过滤:用Set存储忽略字段,只处理科目_部分_类型格式的有效键
  • 正确映射:根据1st/2nd定位到part_1/part_2,将字段值转为数字后赋值到对应属性
  • 动态创建:自动创建不存在的科目或科目部分条目,确保结构完整

运行修正后的代码即可得到预期输出。

内容的提问来源于stack exchange,提问作者Anik Ahmed fathe

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.26 00:43:26