| 网站首页 | 业界新闻 | 小组 | 威客 | 人才 | 下载频道 | 博客 | 代码贴 | 在线编程 | 编程论坛
欢迎加入我们,一同切磋技术
用户名:   
 
密 码:  
共有 937 人关注过本帖
标题:一個学生成績排名的實現程序,以及Custom定制類的用法示例
只看楼主 加入收藏
TonyDeng
Rank: 20Rank: 20Rank: 20Rank: 20Rank: 20
等 级:贵宾
威 望:304
帖 子:25859
专家分:48889
注 册:2011-6-22
结帖率:100%
收藏
 问题点数:0 回复次数:18 
一個学生成績排名的實現程序,以及Custom定制類的用法示例
程序代码:
CLEAR ALL
SET TALK OFF
SET SAFETY OFF
CLOSE DATABASES ALL
CLEAR 

PUBLIC gaSubjects[12]
gaSubjects[1]  = CREATEOBJECT("myField", "化學成績", "S01", "N", 6, 2, .T., 0)
gaSubjects[2]  = CREATEOBJECT("myField", "數學成績", "S02", "N", 6, 2, .T., 0)
gaSubjects[3]  = CREATEOBJECT("myField", "物理成績", "S03", "N", 6, 2, .T., 0)
gaSubjects[4]  = CREATEOBJECT("myField", "語文成績", "S04", "N", 6, 2, .T., 0)
gaSubjects[5]  = CREATEOBJECT("myField", "英語成績", "S05", "N", 6, 2, .T., 0)
gaSubjects[6]  = CREATEOBJECT("myField", "政治成績", "S06", "N", 6, 2, .T., 0)
gaSubjects[7]  = CREATEOBJECT("myField", "化學名次", "R01", "I")
gaSubjects[8]  = CREATEOBJECT("myField", "數學名次", "R02", "I")
gaSubjects[9]  = CREATEOBJECT("myField", "物理名次", "R03", "I")
gaSubjects[10] = CREATEOBJECT("myField", "語文名次", "R04", "I")
gaSubjects[11] = CREATEOBJECT("myField", "英語名次", "R05", "I")
gaSubjects[12] = CREATEOBJECT("myField", "政治名次", "R06", "I")
Create_DataTable(@gaSubjects)

Do_Sort(@gaSubjects)

CLOSE DATABASES ALL
CLEAR ALL 

RETURN 

*---------------------------
* 創建數據表及測試數據
*---------------------------
PROCEDURE Create_DataTable(taSubjects)
    LOCAL lcDataBase, lcTable
    LOCAL lnIndex, lnRecord, lcField
   
    lcDataBase = "Test"
    lcTable = "Scores"
   
    IF !FILE(lcDataBase + ".DBC")
        CREATE DATABASE (lcDataBase)
    ELSE
        OPEN DATABASE (lcDataBase)
    ENDIF
    SET DATABASE TO (lcDataBase)
    IF INDBC(lcTable, "TABLE")
        DROP TABLE (lcTable)
    ENDIF
    CREATE TABLE &lcTable (ID C(10) PRIMARY KEY)
    SELECT (lcTable)
    DBSETPROP(lcTable + ".ID", "FIELD", "Caption", "學號")
    FOR lnIndex = 1 TO ALEN(taSubjects, 1)
        taSubjects[lnIndex].Add_Column
    NEXT
   
    RAND(-1)
    FOR lnRecord = 1 TO 1000
        INSERT INTO &lcTable (ID) VALUES (TRANSFORM(lnRecord, "@L" + REPLICATE("9", 10)))
        FOR lnIndex = 1 TO ALEN(taSubjects, 1) / 2
            lcField = taSubjects[lnIndex].Title
            REPLACE &lcField WITH RAND() * 100
        NEXT
    NEXT 

    USE IN "Scores"
    SET DATABASE TO "Test"
    CLOSE DATABASES
   
ENDPROC 

PROCEDURE Do_Sort(taSubjects)
    LOCAL lnIndex, lcScoreField, lcRankField, lnRank

    OPEN DATABASE "Test"
    USE "Scores" IN 0
   
    SELECT "Scores"
    FOR lnIndex = 1 TO ALEN(taSubjects, 1) / 2
        lcScoreField = taSubjects[lnIndex].Title
        lcRankField = taSubjects[lnIndex + ALEN(taSubjects, 1) / 2].Title
        SET ORDER TO TAG &lcScoreField
        GOTO TOP
        lnRank = 0
        SCAN ALL
            lnRank = lnRank + 1
            REPLACE &lcRankField WITH lnRank
        ENDSCAN
    NEXT
   
    SET ORDER TO TAG ID
    GOTO TOP
    BROWSE
   
    USE IN "Scores"
    SET DATABASE TO "Test"
    CLOSE DATABASES
   
ENDPROC 

DEFINE CLASS myField AS Custom
   
    Caption = ""                && 標題
    Title = ""                  && 字段名
    Type = ""                   && 字段類型
    Width = 0                   && 字段寬度
    Precision = 0               && 字段小數點位數
    IsIndex = .F.               && 是否索引字段
    Ascend = 1                  && 排序方向(1:升序,0:降序)
   
    PROCEDURE Init(tcCaption, tcName, tcType, tnWidth, tnPrecision, tlIndex, tnAscend)
   
        WITH This
            .Caption = tcCaption
            .Title = tcName
            .Type = UPPER(tcType)
            .Width = IIF(!EMPTY(tnWidth), tnWidth, 0)
            .Precision = IIF(!EMPTY(tnPrecision), tnPrecision, 0)
            IF VARTYPE(tlIndex) == "L"
                .IsIndex = tlIndex
            ENDIF
            IF VARTYPE(tnAscend) == "N"
                .Ascend = IIF(tnAscend != 0, 1, 0)
            ENDIF
        ENDWITH
       
    ENDPROC
   
    *------------------------
    * 將字段添加到指定別名的表結構中
    *------------------------
    PROCEDURE Add_Column()
        LOCAL lcDBF, lcString, lcTag
       
        lcDBF = JUSTSTEM(DBF())
        WITH This
            IF TYPE(.Name) == "U"
                lcString = .Title + " " + .Type
                DO CASE
                    CASE INLIST(UPPER(.Type), "C", "Q", "V")
                        lcString = lcString + "(" + TRANSFORM(.Width) + ")"
                    CASE INLIST(UPPER(.Type), "N", "F")
                        lcString = lcString + "(" + TRANSFORM(.Width) + "," + TRANSFORM(.Precision) + ")"
                    CASE UPPER(.Type) == "B"
                        lcString = lcString + "(" + TRANSFORM(.Precision) + ")"
                ENDCASE
                ALTER TABLE &lcDBF ADD COLUMN &lcString
                DBSETPROP(lcDBF + "." + .Title, "FIELD", "Caption", .Caption)
                IF .IsIndex
                    lcTag = .Title
                    IF .Ascend == 1
                        INDEX ON &lcTag TAG &lcTag COLLATE "MACHINE" ASCENDING
                    ELSE
                        INDEX ON &lcTag TAG &lcTag COLLATE "MACHINE" DESCENDING
                    ENDIF
                ENDIF
            ENDIF
        ENDWITH
       
    ENDPROC
   
ENDDEFINE
2014-04-07 21:32
TonyDeng
Rank: 20Rank: 20Rank: 20Rank: 20Rank: 20
等 级:贵宾
威 望:304
帖 子:25859
专家分:48889
注 册:2011-6-22
收藏
得分:0 
問題源自sdta版主的短信。運行本程序之後,會自動在當前目錄生成相關的數據庫和表、索引,打開看看就知道。

[ 本帖最后由 TonyDeng 于 2014-4-7 21:37 编辑 ]

授人以渔,不授人以鱼。
2014-04-07 21:36
TonyDeng
Rank: 20Rank: 20Rank: 20Rank: 20Rank: 20
等 级:贵宾
威 望:304
帖 子:25859
专家分:48889
注 册:2011-6-22
收藏
得分:0 
把原來的一個回覆轉過來:
你那問題,把科目成績和名次安排在表的字段上,設計不大合理,但若是生成的最終表是這樣,倒是可以。當然,直接在這個表上排名,也可以。

授人以渔,不授人以鱼。
2014-04-07 21:45
TonyDeng
Rank: 20Rank: 20Rank: 20Rank: 20Rank: 20
等 级:贵宾
威 望:304
帖 子:25859
专家分:48889
注 册:2011-6-22
收藏
得分:0 
總分排名,自己會加上去麽?

授人以渔,不授人以鱼。
2014-04-07 22:10
sdta
Rank: 20Rank: 20Rank: 20Rank: 20Rank: 20
来 自:江苏省连云港市
等 级:版主
威 望:335
帖 子:9841
专家分:27213
注 册:2012-2-5
收藏
得分:0 
试试,多谢TongDeng版主

坚守VFP最后的阵地
2014-04-07 22:57
TonyDeng
Rank: 20Rank: 20Rank: 20Rank: 20Rank: 20
等 级:贵宾
威 望:304
帖 子:25859
专家分:48889
注 册:2011-6-22
收藏
得分:0 
這個表的結構,應是成績一列直落,不要各科開一個字段,用班級、學號、科目代碼聯合索引,數據都是歸類彙集的,一趟循環即可排名,不用像現在這樣來回掃數次(其實本質上是一樣的,都是遍歷所有成績的記錄,一個是縱向放置,一個是壓扁了放置,數據總量一樣),邏輯較為清晰,代碼也好寫。最終結果出來之後,另外生成一個像現在這樣的臨時表(不用保存的),不過是旋轉數據罷了,如此連不確定科目的考試(比如有些班是不考某些科目的)都能應付,適應性比這個版本還強,這就是遵循數據庫設計規範的好處。

授人以渔,不授人以鱼。
2014-04-07 23:24
sdta
Rank: 20Rank: 20Rank: 20Rank: 20Rank: 20
来 自:江苏省连云港市
等 级:版主
威 望:335
帖 子:9841
专家分:27213
注 册:2012-2-5
收藏
得分:0 
回复 3楼 TonyDeng
原表结构为:(班级,学号,科目,成绩)
最终表结构为:(班级,学号,语文,语文名次,......,总分,总分名次)
名次:同分同名次
运行了你的代码,速度不错,但是这种写法,过去从未试过。
只有慢慢研究,才能摸清你的思路。
这段代码,也是不可多得的好教材。

坚守VFP最后的阵地
2014-04-07 23:31
TonyDeng
Rank: 20Rank: 20Rank: 20Rank: 20Rank: 20
等 级:贵宾
威 望:304
帖 子:25859
专家分:48889
注 册:2011-6-22
收藏
得分:0 
用這個算法,對並列排名的處理,想怎麽處理都可以輕鬆實現,而不用像SQL查詢法那樣費盡腦汁地搞難以閱讀的分組手法,輕微的改動都等於重整算法。

授人以渔,不授人以鱼。
2014-04-07 23:33
TonyDeng
Rank: 20Rank: 20Rank: 20Rank: 20Rank: 20
等 级:贵宾
威 望:304
帖 子:25859
专家分:48889
注 册:2011-6-22
收藏
得分:0 
以下是引用sdta在2014-4-7 23:31:50的发言:

原表结构为:(班级,学号,科目,成绩)
最终表结构为:(班级,学号,语文,语文名次,......,总分,总分名次)
名次:同分同名次
运行了你的代码,速度不错,但是这种写法,过去从未试过。
只有慢慢研究,才能摸清你的思路。
这段代码,也是不可多得的好教材。

班級+學號,就是我現在的ID字段,那是唯一的主鍵索引編碼,等效的。字段的物理排序,衹對我現在生成測試數據有用(亦即利用了前面數組的排列規律,用了除以二這一特徵),但在實際的排名過程中,可以看出是沒有用到那個的,與字段的物理順序無關。

至於執行時間,從生成庫表、測試數據到最終呈現結果,1秒都不到是吧?

思路的關鍵,是動態變換索引!

[ 本帖最后由 TonyDeng 于 2014-4-7 23:39 编辑 ]

授人以渔,不授人以鱼。
2014-04-07 23:37
sdta
Rank: 20Rank: 20Rank: 20Rank: 20Rank: 20
来 自:江苏省连云港市
等 级:版主
威 望:335
帖 子:9841
专家分:27213
注 册:2012-2-5
收藏
得分:0 
如果按照7楼的表结构设计,生成最终排名表,你上面的代码是不是要做大的调整。
班级 学号   科目 成绩  
01   000001 语文   88
01   000001 数学   81
01   000001 物理   72
01   000001 政治   84
01   000001 化学   12
01   000001 英语   65
.
.
40   002651 语文   78
.....................









[ 本帖最后由 sdta 于 2014-4-7 23:51 编辑 ]

坚守VFP最后的阵地
2014-04-07 23:46
快速回复:一個学生成績排名的實現程序,以及Custom定制類的用法示例
数据加载中...
 
   



关于我们 | 广告合作 | 编程中国 | 清除Cookies | TOP | 手机版

编程中国 版权所有,并保留所有权利。
Powered by Discuz, Processed in 0.021616 second(s), 7 queries.
Copyright©2004-2024, BCCN.NET, All Rights Reserved