xyx115 发表于 2019-9-3 21:26:10

删除重复行速度不堪忍受,求效率算法!学习!

gzh888666 发表于 2019-9-3 22:15:50

zghwelcome 发表于 2019-9-3 15:31
简直是灾难性的对比算法
效果杠杠的,不知道高到哪里去了!用在别的程序上也是,我修改了以前的好几个程序。膜拜!我是个菜鸟,见笑了!{:face (87):}

vuivui 发表于 2019-9-4 11:15:19

vb我用过字典对象,没有集合快,在vb这两个方法都是很慢的,同其他算法没法比。
用c语言直接字节或整数“与”最快。
纯au3肯定是慢的,但就这么几行,我想不会慢到哪里去,试试看。

afan 发表于 2019-9-4 11:21:39

vuivui 发表于 2019-9-4 11:15
vb我用过字典对象,没有集合快,在vb这两个方法都是很慢的,同其他算法没法比。
用c语言直接字节或整数“ ...

以前的AU3中 Assign IsDeclared 配合,比字典还快,后来改变了规则,只支持和变量名一致的声明方式就没什么大用处了,在LZ的这个问题基本上只能是字典最快

Dontang2018 发表于 2019-9-4 12:16:42

代码, 我学习一下.

vuivui 发表于 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运用能力也有帮助,我尝试不同方法对比一下,给大家提供个参考。

autoit3CN 发表于 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 对象使用详解

yohoboy 发表于 2019-9-4 23:31:17

參考參考代碼,感謝分享,

vuivui 发表于 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       IfIsDeclared($s[$i]) Then ContinueLoop       Assign($s[$i],0)       $f1&= $s[$i] & @CRLF       $n+= 1NextMsgBox(1, "用时:" & TimerDiff($t),"重行行数:"& $s - $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 + 1]
For $i = 1 To $s
      $slen[$i] = StringLen($s[$i])
Next
For $i = 1 To $s
      If $slen[$i] = 0 Then ContinueLoop
      For $j = $i + 1 To $s
                ;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 - $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 + 1]
For $i = 1 To $s
      $slen[$i] = StringLen($s[$i])
Next
For $i = 1 To $s
      If $slen[$i] = 0 Then ContinueLoop
      For $j = $i + 1 To $s
                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 - $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
      If $o.Exists($s[$i]) Then ContinueLoop
      $o.Add($s[$i], 0)
      $f1 &= $s[$i] & @CRLF
      $n += 1
Next

MsgBox(1, "用时:" & TimerDiff($t), "重行行数:" & $s - $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语言常用优化手段,楼主文本的行首数字都作了删除处理,因为这里只是为了检测去除重复行的速度,几个方法的去重数有出入,是换行的计算问题,懒得作修正了。



afan 发表于 2019-9-5 16:02:20

vuivui 发表于 2019-9-5 15:22
测试结果:

方法一(Assign):


的确跟预想的差不多~
我现在遇到去重的问题,除了短字符串类用正则,其它场合能用Asign的尽量使用。
虽然很早已经是用的不支持任意字符Asign,但一般只要多两步转换(小写、Bin)再Asign,因为效率仍然很刚。
较复杂的就直接字典吧,虽然几乎没实际遇到过需要的场景

vuivui 发表于 2019-9-5 16:03:31

因为行长不一,所以用了长度比较,节约了一些用时。

如果几万甚至上百万行(我经常遇到的),要用Assign法,比vb集合法还快,但用时还是多,可用vb进行二进制比较,最好直接用C,相当于拖拉机变飞机了。

vuivui 发表于 2019-9-5 16:26:36

afan 发表于 2019-9-5 16:02
的确跟预想的差不多~
我现在遇到去重的问题,除了短字符串类用正则,其它场合能用Asign的尽量使用。
虽 ...

au3我一直用的是Assign,正则是要用的,一行内找重复字符串很好用。

heavenm 发表于 2019-9-6 00:58:04

看看是什么高级功能

862228699 发表于 2019-9-6 21:06:44

效率比较高的应该就是字典了!

kevinch 发表于 2019-9-28 17:13:11

字典超过一定量级后会变慢,不过有办法解决
页: 1 [2] 3
查看完整版本: 删除重复行速度不堪忍受,求效率算法!(已解决)