0

我教一个 9 个单元的班级,学生可以通过每个单元以“及格”、“优异”或“优异”的成绩通过。AP 获得 70 分,M 获得 80 分,D 获得 90 分。今年的总体结果是所有单元的总分。

他们需要在允许“M”标准之前通过所有“P”标准,并且在允许“D”标准之前他们需要所有“M”标准。P/M/D 标准的数量因单位而异。以下学生在本单元中取得了“及格”(70 分),因为即使他获得了所有 D 标准,他也没有获得 M:

单元 1 - 脑外科

P1 - 知道大脑在哪里 - 通过
P2 - 知道哪条路向上 - 通过
M1 - 解释大脑做什么 - 通过
M2 - 男性和女性大脑之间是否存在差异 - 失败
D1 - 弄清楚为什么我的大脑可以t 解决这个问题 - 通过
D2 - 发明一种药物,让大脑立即弄清楚逻辑 - 通过
D3 - 找到一种仅靠脑力就能赚很多钱的方法 - 通过

我有一个SqlDataReader,它用这些列填充DataTable:unitNo、criteriaName、criteriatype(即P/M/D)、passedOrFailed。该查询已按个别学生进行选择,因此 DataTable 仅包含一名学生的记录。它看起来像这样:

UnitNo   Citerion   Type   passed?  
1        know etc     P       Yes  
1        know etc     P       Yes  
1        explain etc  M       Yes  
1        is there etc M       No  
1        Figure etc   D       Yes  
1        invent etc   D       Yes  
1        find etc     D       Yes  
2        blah etc     P       Yes  
2        wot etc      P       Yes  
2        so etc       M       No 

我正在寻找一个看起来像这样的数据表:

UnitNo  P    M   D   Points  
1       Y    N   Y     70  
2       Y    Y   N     80  
3       N    N   N      0  
4       N    Y   Y      0  
5       Y    Y   Y     90  

………………………………………………………………………………………………………………………………………………
_
_

最后总分 - 学生有 240 分。

我对 DataTables、c# 等非常满意,这是让我陷入困境的逻辑。我写的每一段代码在大约 2 行之后看起来都像意大利面条。

有没有人有一些关于整理这个逻辑的指示?就像古尔蒙哈斯特学校里的场景……如果你能解决的话,我会亲自派老婆去给你做周日烤肉。

个人电脑


好的,这是包含 CSharper 答案的实际代码(也进行了编辑以添加他的额外列名的解决方案)。这显然是正确的解决方案,我只是没有完全让数字出现(我发现他在 DataRow 演员表后遗漏了括号,但这不是问题)。我在最后连接了几个测试网格以显示结果。另外,我不是 linq 人,所以我不知道如何将第一个表中的单位名称添加到第二个表中,或者总分:

(注意,我使用 1 = 未标记,2 = 失败,3 = 通过 passFail 字段)

//create the sql to extract the data
        String sqlString = "SELECT unitNo, unitName, criterionPMD, passFail FROM unitDetails INNER JOIN unitStudentRecord ON unitDetails.id = unitStudentRecord.unitDetailsId INNER JOIN unitSummary ON unitDetails.unitSummaryId = unitSummary.id WHERE studentID = '" + ((String)Session["studentID"]).Trim() + "'";
        SqlConnection conn = new SqlConnection(ConfigurationManager.ConnectionStrings["studentTutorialsConnectionString"].ConnectionString);
        SqlCommand sqlComm = new SqlCommand(sqlString, conn);
        conn.Open();
        SqlDataReader sqlTotalMarks = sqlComm.ExecuteReader();

        //create the workings out datatable and fill it
        DataTable dtWorkings = new DataTable();
        dtWorkings.Load(sqlTotalMarks);
        conn.Close();

        // create the results datatable
        DataTable dtResults = new DataTable();
        dtResults.Columns.Add("units", typeof(int));
        dtResults.Columns.Add("name", typeof(string));
        dtResults.Columns.Add("P", typeof(bool));
        dtResults.Columns.Add("M", typeof(bool));
        dtResults.Columns.Add("D", typeof(bool));
        dtResults.Columns.Add("points", typeof(int));

        //fill the results table
        foreach (var units in dtWorkings.Rows.Cast<DataRow>().GroupBy(r => r["unitNo"]))
        {
            var p = units.Where(r => r["criterionPMD"] == "P").All(r => r["passFail"] == "3");
            var m = units.Where(r => r["criterionPMD"] == "M").All(r => r["passFail"] == "3");
            var d = units.Where(r => r["criterionPMD"] == "D").All(r => r["passFail"] == "3");
            dtResults.Rows.Add(
                 units.Key,//UnitNo
                 units.Select(r => r["unitName"]).First(),//UnitName                    
                 p,
                 m,
                 d,
                 p ? (m ? (d ? 90 : 80) : 70) : 0);//Points
        }

        gvTemp.DataSource = dtWorkings;
        gvTemp.DataBind();
        gvSummary.DataSource = dtResults;
        gvSummary.DataBind();

这是 gvTemp 的网格:

   unitNo   unitName       criterionPMD passFail
    2     Computer systems  P     3
    2     Computer systems  P     1
    3     Web rubbish           P     3

这是 gvSummary 的网格:

units   name               P     M  D   points
2           Computer systems            90   
3           Web rubbish                             90

在 gvSummary 网格中,所有 PMD 标准都出现了勾选的复选框,但没有总计。我期待第 2 单元的分数为零,第 3 单元的分数为 70 分……

好近啊……

4

1 回答 1

1

使用 C# 类执行此操作可能有助于将问题分解为更小的部分并获得更好的可维护解决方案。但是,使用DataTable. 数据表的另一个缺点是数据不容易实现类型安全。在此答案的第一个版本中,缺少 r["criterionPMD"] 到字符串的转换,因此存在参考比较而不是字符串比较。

            //create the workings out datatable and fill it
            DataTable dtWorkings = new DataTable();
            dtWorkings.Columns.Add("unitNo", typeof(int));
            dtWorkings.Columns.Add("unitName", typeof(string));
            dtWorkings.Columns.Add("criterionPMD", typeof(string));
            dtWorkings.Columns.Add("passFail", typeof(int));

            dtWorkings.Rows.Add(2, "Computer systems", "P", 3);
            dtWorkings.Rows.Add(2, "Computer systems", "P", 2);
            dtWorkings.Rows.Add(3, "Web rubbish", "P", 3);

            // create the results datatable
            DataTable dtResults = new DataTable();
            dtResults.Columns.Add("units", typeof(int));
            dtResults.Columns.Add("name", typeof(string));
            dtResults.Columns.Add("P", typeof(bool));
            dtResults.Columns.Add("M", typeof(bool));
            dtResults.Columns.Add("D", typeof(bool));
            dtResults.Columns.Add("points", typeof(int));

            //fill the results table
            foreach (var units in dtWorkings.Rows.Cast().GroupBy(r => r["unitNo"]))
            {
                var p = units.Where(r => (string)r["criterionPMD"] == "P").All(r => (int)r["passFail"] == 3);
                var m = units.Where(r => (string)r["criterionPMD"] == "M").All(r => (int)r["passFail"] == 3);
                var d = units.Where(r => (string)r["criterionPMD"] == "D").All(r => (int)r["passFail"] == 3);
                dtResults.Rows.Add(
                     units.Key,//UnitNo
                     units.Select(r => r["unitName"]).First(),//UnitName                    
                     p,
                     m,
                     d,
                     p ? (m ? (d ? 90 : 80) : 70) : 0);//Points
            }

使用复杂的条件表达式,您可以确保仅在满足所有 p、m 和 d 标准时才给出 90 分。

即使在只有通过和区分标准的单元中,这也会给出正确的结果,因此只有 90、70 或 0 分是可能的。不知道这对你有没有要求。

In your example with only "P" criteria it's difficult to decide if 70 or 90 points are the correct result. This code snippet checks if all P, M and D criteria are fulfilled and in this case gives 90 points even if there is no M or D criteria and all P criteria were passed. I think in all your real-world scenarios you won't have this edge case but anyway it's worth thinking about this.

于 2013-01-06T14:35:40.880 回答