找回密码
 加入
搜索
楼主: gzh888666

[AU3基础] 删除重复行速度不堪忍受,求效率算法!(已解决)

[复制链接]
发表于 2019-9-3 21:26:10 | 显示全部楼层
删除重复行速度不堪忍受,求效率算法!学习!
 楼主| 发表于 2019-9-3 22:15:50 | 显示全部楼层
zghwelcome 发表于 2019-9-3 15:31
简直是灾难性的对比算法

效果杠杠的,不知道高到哪里去了!用在别的程序上也是,我修改了以前的好几个程序。膜拜!我是个菜鸟,见笑了!
发表于 2019-9-4 11:15:19 | 显示全部楼层
vb我用过字典对象,没有集合快,在vb这两个方法都是很慢的,同其他算法没法比。
用c语言直接字节或整数“与”最快。
纯au3肯定是慢的,但就这么几行,我想不会慢到哪里去,试试看。
发表于 2019-9-4 11:21:39 | 显示全部楼层
vuivui 发表于 2019-9-4 11:15
vb我用过字典对象,没有集合快,在vb这两个方法都是很慢的,同其他算法没法比。
用c语言直接字节或整数“ ...

以前的AU3中 Assign IsDeclared 配合,比字典还快,后来改变了规则,只支持和变量名一致的声明方式就没什么大用处了,在LZ的这个问题基本上只能是字典最快
发表于 2019-9-4 12:16:42 | 显示全部楼层
代码, 我学习一下.
发表于 2019-9-4 13:28:24 | 显示全部楼层
afan 发表于 2019-9-4 11:21
以前的AU3中 Assign IsDeclared 配合,比字典还快,后来改变了规则,只支持和变量名一致的声明方式就没什 ...

我记得你Assign用得很多,我过去一直用3361,后来因为要用到DllCallAddress,就用了3380没换过。办公老电脑用的是xp,没发现有什么问题,家里笔记本用的是win7,好像也能用,可能是我au3编的多是小脚本吧。

Assign用起来跟字典一样,很方便,如果低版本够用,且没遇到问题的话,用低版本也行,或者两个版本一起用,我曾经改个扩展名,多版本同时用。

对象我过去用的多,现在用得少,因为调用API函数更直接。撇开au3标准函数,调用API函数比对象更方便,更容易理解,C语言调用API函数直接、高效,所以我经常是用C编个dll,然后au3调用。C语言用起来跟au3很相近,就是声明变量、字符串操作麻烦些。其实au3标准函数大多是直接调用API函数,或者简单的组合。

如果文本有几万行,因性能问题,不得不考虑C语言协助,像楼主说的情况,就几百行,应该是au3可以满足需求的。使用字典对象是一个办法,直接用au3编也有必要,毕竟不是什么情况都能用到对象,另外对提高au3运用能力也有帮助,我尝试不同方法对比一下,给大家提供个参考。

评分

参与人数 2金钱 +40 贡献 +3 收起 理由
gzh888666 + 10 + 2 感谢,对一个业余切没有其他任何编程经验的.
afan + 30 + 1 经验之谈

查看全部评分

发表于 2019-9-4 21:50:40 | 显示全部楼层
本帖最后由 autoit3CN 于 2019-9-4 21:58 编辑

AU3之Script.Dictionary字典对象初探,感兴趣!
http://www.autoitx.com/thread-37424-1-1.html
Dictionary 对象使用详解

评分

参与人数 1金钱 +10 贡献 +2 收起 理由
gzh888666 + 10 + 2

查看全部评分

发表于 2019-9-4 23:31:17 | 显示全部楼层
參考參考代碼,感謝分享,
发表于 2019-9-5 15:22:12 | 显示全部楼层
本帖最后由 vuivui 于 2019-9-5 15:41 编辑

测试结果:

方法一(Assign):
Local $f, $f1, $s, $n = 0
$f = FileRead("题库.txt")
$s = StringRegExpReplace($f,'(?m)^\d+.\s*', "")
$s = StringSplit($s, @CRLF, 1)

Local $t = TimerInit()
For $i = 1 To $s[0]
       IfIsDeclared($s[$i]) Then ContinueLoop
       Assign($s[$i],0)
       $f1&= $s[$i] & @CRLF
       $n+= 1
Next
MsgBox(1, "用时:" & TimerDiff($t),"重行行数:"& $s[0] - $n)
$file = FileOpen("f1.txt", 2)
FileWrite($file, $f1)
FileClose($file)
ShellExecute("f1.txt")

方法二(字符逐个比较):

Local $f, $f1, $s, $n = 0
$f = FileRead("题库.txt")
$s = StringRegExpReplace($f, '(?m)^\d+.\s*', "")
$s = StringSplit($s, @CRLF, 1)

Local $t = TimerInit()
Local $slen[$s[0] + 1]
For $i = 1 To $s[0]
        $slen[$i] = StringLen($s[$i])
Next
For $i = 1 To $s[0]
        If $slen[$i] = 0 Then ContinueLoop
        For $j = $i + 1 To $s[0]
                ;If $slen[$i] = $slen[$j] And $s[$i]==$s[$j] Then $slen[$j]=0               
                If $slen[$i] = $slen[$j] Then
                        For $k = 1 To $slen[$i]
                                ;If BitXOR(AscW(StringMid($s[$i], $k, 1)), AscW(StringMid($s[$j], $k, 1))) Then ExitLoop
                                If StringMid($s[$i], $k, 1) <> StringMid($s[$j], $k, 1) Then ExitLoop
                                If $k = $slen[$i] Then $slen[$j] = 0
                        Next
                EndIf
        Next
        $f1 &= $s[$i] & @CRLF
        $n += 1
Next

MsgBox(1, "用时:" & TimerDiff($t), "重行行数:" & $s[0] - $n)
$file = FileOpen("f1.txt", 2)
FileWrite($file, $f1)
FileClose($file)
ShellExecute("f1.txt")


方法三(字符串比较):

Local $f, $f1, $s, $n = 0
$f = FileRead("题库.txt")
$s = StringRegExpReplace($f, '(?m)^\d+.\s*', "")
$s = StringSplit($s, @CRLF, 1)

Local $t = TimerInit()
Local $slen[$s[0] + 1]
For $i = 1 To $s[0]
        $slen[$i] = StringLen($s[$i])
Next
For $i = 1 To $s[0]
        If $slen[$i] = 0 Then ContinueLoop
        For $j = $i + 1 To $s[0]
                If $slen[$i] = $slen[$j] And $s[$i]==$s[$j] Then $slen[$j]=0               
        Next
        $f1 &= $s[$i] & @CRLF
        $n += 1
Next

MsgBox(1, "用时:" & TimerDiff($t), "重行行数:" & $s[0] - $n)
$file = FileOpen("f1.txt", 2)
FileWrite($file, $f1)
FileClose($file)
ShellExecute("f1.txt")

方法四(字典对象):

Local $f, $f1, $s, $n = 0
$f = FileRead("题库.txt")
$s = StringRegExpReplace($f, '(?m)^\d+.\s*', "")
$s = StringSplit($s, @CRLF, 1)

Local $t = TimerInit()
Local $o = ObjCreate('Scripting.Dictionary')
For $i = 1 To $s[0]
        If $o.Exists($s[$i]) Then ContinueLoop
        $o.Add($s[$i], 0)
        $f1 &= $s[$i] & @CRLF
        $n += 1
Next

MsgBox(1, "用时:" & TimerDiff($t), "重行行数:" & $s[0] - $n)
$file = FileOpen("f1.txt", 2)
FileWrite($file, $f1)
FileClose($file)
ShellExecute("f1.txt")



把方法一(Assign)用时设为1,用时比例如下:
方法一:
1
方法二:
265
方法三:
213
方法四:
3

结果同预想的差不多,字典对象法用时是Assign法的3倍,字符串比较法看起来用时多,实际在我办公的老爷子机上也就用了4秒。

因为楼主提供的文本行字符串长,所以用时多,简单文本的处理这几个方法都能用,字符比较与字符串比较方法对理解au3编程有好处,实际碰到的问题往往不是删除重复行那么简单。

异或法注释在方法二中,慢了一点点,这个方法是C语言常用优化手段,楼主文本的行首数字都作了删除处理,因为这里只是为了检测去除重复行的速度,几个方法的去重数有出入,是换行的计算问题,懒得作修正了。



评分

参与人数 2金钱 +130 贡献 +22 收起 理由
gzh888666 + 80 + 20 赞一个!学习到了!
afan + 50 + 2 赞一个!

查看全部评分

发表于 2019-9-5 16:02:20 | 显示全部楼层
vuivui 发表于 2019-9-5 15:22
测试结果:

方法一(Assign):

的确跟预想的差不多~
我现在遇到去重的问题,除了短字符串类用正则,其它场合能用Asign的尽量使用。
虽然很早已经是用的不支持任意字符Asign,但一般只要多两步转换(小写、Bin)再Asign,因为效率仍然很刚。
较复杂的就直接字典吧,虽然几乎没实际遇到过需要的场景
发表于 2019-9-5 16:03:31 | 显示全部楼层
因为行长不一,所以用了长度比较,节约了一些用时。

如果几万甚至上百万行(我经常遇到的),要用Assign法,比vb集合法还快,但用时还是多,可用vb进行二进制比较,最好直接用C,相当于拖拉机变飞机了。
发表于 2019-9-5 16:26:36 | 显示全部楼层
afan 发表于 2019-9-5 16:02
的确跟预想的差不多~
我现在遇到去重的问题,除了短字符串类用正则,其它场合能用Asign的尽量使用。
虽 ...

au3我一直用的是Assign,正则是要用的,一行内找重复字符串很好用。
发表于 2019-9-6 00:58:04 | 显示全部楼层
看看是什么高级功能
发表于 2019-9-6 21:06:44 | 显示全部楼层
效率比较高的应该就是字典了!
发表于 2019-9-28 17:13:11 | 显示全部楼层
字典超过一定量级后会变慢,不过有办法解决
您需要登录后才可以回帖 登录 | 加入

本版积分规则

QQ|手机版|小黑屋|AUTOIT CN ( 鲁ICP备19019924号-1 )谷歌 百度

GMT+8, 2024-11-16 08:48 , Processed in 0.091258 second(s), 20 queries .

Powered by Discuz! X3.5 Licensed

© 2001-2024 Discuz! Team.

快速回复 返回顶部 返回列表