标题:提高代码的运行速度
只看楼主
sdta
Rank: 20Rank: 20Rank: 20Rank: 20Rank: 20
来 自:江苏省连云港市
等 级:版主
威 望:323
帖 子:9621
专家分:26174
注 册:2012-2-5
得分:0 
以下是引用ycvf在2021-4-1 17:44:23的发言:

这个函数GETWORDNUM(jmss1, lnj, ",")没见过,有知道的吗、

VFP9 版本中的一个函数,大体意思:从一个字符串中返回指定单词。

坚守VFP最后的阵地
2021-04-01 17:48
sdta
Rank: 20Rank: 20Rank: 20Rank: 20Rank: 20
来 自:江苏省连云港市
等 级:版主
威 望:323
帖 子:9621
专家分:26174
注 册:2012-2-5
得分:0 
以下是引用厨师王德榜在2021-4-1 17:15:35的发言:

我的代码,按照要求不用任何Select ... 语句 ,另辟蹊径用了字典对象,供大家参考:
IF NOT USED('sp') THEN
    USE "C:\sp.dbf" IN 0 EXCLUSIVE  &&  改成你的路径
ENDIF
LOCAL icnt as Integer ,ii as Integer
LOCAL ckey as String ,str1 as String
LOCAL time11 as Datetime ,time22 as Datetime

IF  USED('result1') THEN
    USE IN result1
ENDIF

LOCAL  oDic As Object
oDic = CreateObject("Scripting.Dictionary")
time11 = SECONDS()
SELECT sp
GO TOP
SCAN
    str1 = ALLTRIM(sp.jmss1)
    icnt = ALINES(arr2,str1,1,",")
    FOR ii =1 TO icnt
        ckey = LTRIM(STR(ii)) - "_" - arr2(ii)
        IF odic.Exists(ckey) THEN
            odic.Item(ckey) = odic.Item(ckey) + 1
        ELSE
            odic.Add( ckey,1) &&
        ENDIF     
    ENDFOR

ENDSCAN

DIMENSION arrKey(1) as String
arrKey =odic.Keys

CREATE CURSOR result1 (第几题 c(4) , 分值 c(4),次数 i )
FOR ii = 1 TO odic.Count  &&
*!*        tmp11 = LEFT(arrKey(ii), AT('_',arrKey(ii)) -1)
*!*        tmp22 = SUBSTR(arrKey(ii), AT('_',arrKey(ii)) +1)
*!*        tmp33 = odic.Item(arrKey(ii))
   
    INSERT INTO result1 (第几题  , 分值 ,次数  ) ;
        VALUES ( LEFT(arrKey(ii), AT('_',arrKey(ii)) -1),  ;
                SUBSTR(arrKey(ii), AT('_',arrKey(ii)) +1), ;
                odic.Item(arrKey(ii)) )
ENDFOR
time22 = SECONDS()
odic.RemoveAll
RELEASE oDic
SELECT result1
INDEX on 第几题 + 分值 TO 'C:\ind12'   &&  改成你的路径

BROWSE TITLE "总耗时" +  LTRIM(STR(time22 - time11 ,14,4 ))

在我的电脑上运行结果:

独辟蹊径,别具一格,方法学习了,速度不理想。

[此贴子已经被作者于2021-4-1 18:34编辑过]

收到的鲜花
  • 瓜瓜19902021-04-01 20:37 送鲜花  1朵  

坚守VFP最后的阵地
2021-04-01 18:31
schtg
Rank: 11Rank: 11Rank: 11Rank: 11
来 自:https://t.me/pump_upp
等 级:贵宾
威 望:67
帖 子:1355
专家分:2534
注 册:2012-2-29
得分:5 
回复 17楼 厨师王德榜
学习啦,谢谢!
2021-04-01 18:39
sdta
Rank: 20Rank: 20Rank: 20Rank: 20Rank: 20
来 自:江苏省连云港市
等 级:版主
威 望:323
帖 子:9621
专家分:26174
注 册:2012-2-5
得分:0 
经过分析影响速度的主要原因是子字符串截取的速度上,在子字符串长度一样的情况下,SUBSTR()速度是最快的,但在本题子字符串的长度不一样的情况下SUBSTR()就用不上了,VFP9中的其它几个函数如:GETWORDNUM()、ALINES()等函数均不理想,只有另起炉灶了。

坚守VFP最后的阵地
2021-04-01 20:49
吹水佬
Rank: 20Rank: 20Rank: 20Rank: 20Rank: 20
等 级:版主
威 望:432
帖 子:10064
专家分:41463
注 册:2014-5-20
得分:60 
SUBSTR() + AT() 就可以,但字符串不长,与GETWORDNUM()差别不大。ALINES()因要分配内存和读写操作会耗费一些。

程序代码:
DIMENSION az[100]
USE sp
t1 = SECONDS()
n = GETWORDCOUNT(jmss1, ",") 
FOR i=1 TO n
    STORE 0 TO az
    SCAN
        j = (VAL(GETWORDNUM(jmss1,i,","))+1) * 10
        az[j] = az[j]+1
    ENDSCAN
ENDFOR
? SECONDS() - t1
FOR i=1 TO 100
    IF az[i] > 0
        ? i/10-1, az[i]
    ENDIF
ENDFOR
收到的鲜花
  • 瓜瓜19902021-04-01 21:44 送鲜花  2朵  
  • schtg2021-04-03 05:46 送鲜花  2朵  
2021-04-01 21:07
吹水佬
Rank: 20Rank: 20Rank: 20Rank: 20Rank: 20
等 级:版主
威 望:432
帖 子:10064
专家分:41463
注 册:2014-5-20
得分:0 
2021-04-01 21:16
sdta
Rank: 20Rank: 20Rank: 20Rank: 20Rank: 20
来 自:江苏省连云港市
等 级:版主
威 望:323
帖 子:9621
专家分:26174
注 册:2012-2-5
得分:0 
以下是引用吹水佬在2021-4-1 21:07:26的发言:

SUBSTR() + AT() 就可以,但字符串不长,与GETWORDNUM()差别不大。ALINES()因要分配内存和读写操作会耗费一些。

DIMENSION az[100]
USE sp
t1 = SECONDS()
n = GETWORDCOUNT(jmss1, ",")
FOR i=1 TO n
    STORE 0 TO az
    SCAN
        j = (VAL(GETWORDNUM(jmss1,i,","))+1) * 10
        az[j] = az[j]+1
    ENDSCAN
ENDFOR
? SECONDS() - t1

FOR i=1 TO 100
    IF az[i] > 0
        ? i/10-1, az[i]
    ENDIF
ENDFOR

吹版的代码在我的电脑上运行时间为1.2秒左右


吹版的代码精简效率高,我的又一个版本也是你这个数组思路,但是代码比你的多了不少行,判断也多,故而效率也低了不少,向吹版学习致敬!
程序代码:
T1 = SECONDS()
CLOSE DATABASES 
USE 选择\sp ALIAS aa
ln = OCCURS(",", jmss1) + 1 && 获取题目的数量
FOR lnj = 1 TO ln
    lnCnt = 0
    RELEASE la
    LOCAL la[10, 2]
    SCAN
        lnfz = VAL(GETWORDNUM(jmss1, lnj, ",")) &&VAL(SUBSTR(jmss1, 2 *lnj - 1, 1))
        IF ASCAN(la, lnfz, 1, ALEN(la, 1), 1) = 0
            lnCnt = lnCnt + 1
            la[lnCnt, 1] = lnfz
            la[lnCnt, 2] = 1
        ELSE 
            lnRow = (ASCAN(la, lnfz, 1, ALEN(la, 1), 1) + 1) / 2
            la[lnRow, 2] = la[lnRow, 2] + 1
        ENDIF 
    ENDSCAN 
ENDFOR 
MESSAGEBOX(SECONDS() - T1)
FOR lnj = 1 TO ALEN(la, 1)
    IF ASCAN(la, .F., 1, ALEN(la, 1), 1) > 0
        lnCnt = (ASCAN(la, .F., 1, ALEN(la, 1), 1) + 1) / 2
        EXIT 
    ENDIF 
ENDFOR
DIMENSION la(lnCnt - 1, 2)
ASORT(la)
LIST MEMORY LIKE la && 最后一题的数组结果

我的这段代码运行时间为2.4秒左右

[此贴子已经被作者于2021-4-1 21:26编辑过]


坚守VFP最后的阵地
2021-04-01 21:20
sdta
Rank: 20Rank: 20Rank: 20Rank: 20Rank: 20
来 自:江苏省连云港市
等 级:版主
威 望:323
帖 子:9621
专家分:26174
注 册:2012-2-5
得分:0 
回复 26楼 吹水佬
结果完全正确
因为后期还要处理每题的其它几个指标:如平均分,最高分,满分率,零分率,有了分值及对应的人数,计算这几个指标的运行时间可以忽略不计。这是去年帮别人做的一个指标统计处理小程序,当时用的就是瓜瓜在前面贴出的SQL代码,最近闲来无事,把这个问题重新找出来了,看只用VFP命令(不用SQL查询)与SQL查询时间的差距有多大,现在看来运行时间差不多,大约3-5秒左右的误差。考试科目共7门,现在讨论的题目只是其中的一门,还有一门课程的题目有50多题,刚才运行了吹版的代码,运行时间在17秒左右。如果试题在10题内,每题运行时间在0.15秒,但是55题每题运行时间在0.3秒左右,这是什么原因?吹版能帮解释一下吗

坚守VFP最后的阵地
2021-04-01 21:50
ycvf
Rank: 2
等 级:论坛游民
帖 子:209
专家分:56
注 册:2012-8-25
得分:0 
回复 21楼 sdta
能举例说明吗?

落花人独立,微雨燕双飞。
2021-04-01 21:57
sdta
Rank: 20Rank: 20Rank: 20Rank: 20Rank: 20
来 自:江苏省连云港市
等 级:版主
威 望:323
帖 子:9621
专家分:26174
注 册:2012-2-5
得分:0 
以下是引用ycvf在2021-4-1 21:57:55的发言:

能举例说明吗?

? GETWORDNUM("A,B,CW, D890,    123E", 5, ",")

[此贴子已经被作者于2021-4-1 22:04编辑过]


坚守VFP最后的阵地
2021-04-01 22:00



参与讨论请移步原网站贴子:https://bbs.bccn.net/thread-505310-1-1.html




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

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