【问题标题】:Needing Help on a Loop for averaging grades using awk. Output prints the same grade for every student在循环上需要帮助以使用 awk 平均成绩。输出为每个学生打印相同的成绩
【发布时间】:2020-04-13 02:39:49
【问题描述】:
BEGIN {
    FS=","
    OFS = "\t" 
    OFMT = "%.2f"
    }

$4~/[0-9]/ {

    EARN[$1$2]+=$4
    POS[$1$2]+=$5
    CLASS[$1]++
    TYPE[$2]++
}
END{ 
    TOTAL=0
    for (STUDENT in CLASS){ 

        HW=(EARN[$1"Homework"]/POS[$1"Homework"])*0.30
        LAB=(EARN[$1"Lab"]/POS[$1"Lab"])*0.50
        QUIZ=(EARN[$1"Quiz"]/POS[$1"Quiz"])*0.10
        FINAL=(EARN[$1"Final"]/POS[$1"Final"])*0.10
        WS=(EARN[$1"Survey"]/POS[$1"Survey"])*0.10
        TOTAL=(HW+LAB+QUIZ+FINAL+WS)*100
        GRADE= "A"

        if (TOTAL < 90) {
            GRADE="B"
        }
        if ( TOTAL < 80){
            GRADE="C"
        }
        if (TOTAL < 70){
            GRADE="D"
        }
        if( TOTAL < 60) {
            GRADE="E"
        }

    }
    print "Student\t Total \t Letter Grade"
        print STUDENT, TOTAL, "\t" GRADE    
}

代码 /should/ 为每个学生提供一个唯一的成绩,但是对于我的示例文件,每个学生都获得相同的成绩(我假设这是第一个学生的成绩),代码正在通过第 4 列 EARN(获得的分数)并将其与 $5 POS 列(可能的点数)进行比较

【问题讨论】:

    标签: for-loop if-statement awk


    【解决方案1】:

    您的脚本有 2 个主要问题(但做得很好,也很努力——您已经很接近了)。首先是您需要移动您的打印语句。 END的第一个到开头,例如

    END{ 
        print "Student\t Total \t Letter Grade"
    

    for (STUDENT in CLASS){ 循环中的下一个,例如

            if( TOTAL < 60) {
                GRADE="E"
            }
    
            print STUDENT, TOTAL, "\t" GRADE    
        }
    }
    

    第二个也是最有问题的错误是使用$1,例如HW=(EARN[$1"Homework"]/...,而不是使用STUDENT(这是您的循环变量),例如HW=(EARN[STUDENT"Homework"]/...

    除了第二个,在您的计算中,如果学生没有特定成绩(如您在评论中提供的数据中的 "Survey""Final"),您将收到除以零作为不会有对应的,例如POS[STUDENT"Survey"] 将被视为零。

    您可以使用三元来避免这种情况,以确保元素非零或使用 1 作为值,例如而不是:

        FINAL=(EARN[STUDENT"Final"]/POS[STUDENT"Final"])*0.10
    

    你可以使用:

        FINAL=(EARN[STUDENT"Final"]/(POS[STUDENT"Final"] ? POS[STUDENT"Final"] : 1))*0.10
    

    (如果索引不在POS 数组中,这只是确保分母是1

    通过该更改,您可以使用:

    #!/bin/awk -f
    
    BEGIN {
        FS=","
        OFS = "\t" 
        OFMT = "%.2f"
    }
    
    $4~/[0-9]/ {
    
        EARN[$1$2]+=$4
        POS[$1$2]+=$5
        CLASS[$1]++
        TYPE[$2]++
    }
    END{ 
        print "Student\t Total \t Letter Grade"
        TOTAL=0
        for (STUDENT in CLASS){ 
    
            HW=(EARN[STUDENT"Homework"]/(POS[STUDENT"Homework"] ? POS[STUDENT"Homework"] : 1))*0.30
            LAB=(EARN[STUDENT"Lab"]/(POS[STUDENT"Lab"] ? POS[STUDENT"Lab"] : 1))*0.50
            QUIZ=(EARN[STUDENT"Quiz"]/(POS[STUDENT"Quiz"] ? POS[STUDENT"Quiz"] : 1))*0.10
            FINAL=(EARN[STUDENT"Final"]/(POS[STUDENT"Final"] ? POS[STUDENT"Final"] : 1))*0.10
            WS=(EARN[STUDENT"Survey"]/(POS[STUDENT"Survey"] ? POS[STUDENT"Survey"] : 1))*0.10
            TOTAL=(HW+LAB+QUIZ+FINAL+WS)*100
            GRADE= "A"
    
            if (TOTAL < 90) {
                GRADE="B"
            }
            if ( TOTAL < 80){
                GRADE="C"
            }
            if (TOTAL < 70){
                GRADE="D"
            }
            if( TOTAL < 60) {
                GRADE="E"
            }
    
            print STUDENT, TOTAL, "\t" GRADE    
        }
    }
    

    (注意:我会使用"F"作为最终成绩而不是"E"——从来没有听说过那个...,并且也使用小写 em> 用户变量的名称)

    使用/输出示例

    根据您提供的数据,您将收到:

    $ ./calcgrades.awk grades.txt
    Student  Total   Letter Grade
    Chelsey 86.89           B
    Sam     40.77           E
    

    如果您有任何问题,请告诉我。

    【讨论】:

    • 哇,谢谢你,感谢你帮我解决这个问题!我为糟糕的数据格式道歉。在过去几天的大部分时间里,我一直坚持下去。
    • 这是一个树木问题的森林——你可以看几天而不是突然意识到你应该使用STUDENT而不是$1(发生在我们所有人身上)- - 欢迎编程和编写脚本:)
    猜你喜欢
    • 2016-02-11
    • 1970-01-01
    • 1970-01-01
    • 2014-11-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-01-02
    相关资源
    最近更新 更多