ExcelHome技术论坛

 找回密码
 免费注册

QQ登录

只需一步,快速开始

快捷登录

搜索
EH技术汇-专业的职场技能充电站 妙哉!函数段子手趣味讲函数 Excel服务器-会Excel,做管理系统 效率神器,一键搞定繁琐工作
HR薪酬管理数字化实战 Excel 2021函数公式学习大典 Excel数据透视表实战秘技 打造核心竞争力的职场宝典
让更多数据处理,一键完成 数据工作者的案头书 免费直播课集锦 ExcelHome出品 - VBA代码宝免费下载
用ChatGPT与VBA一键搞定Excel WPS表格从入门到精通 Excel VBA经典代码实践指南
楼主: 吴中泉

[讨论] 提取任意多行多列中每列都有的重复值,数据量大速度快

[复制链接]

TA的精华主题

TA的得分主题

 楼主| 发表于 2023-3-29 20:13 | 显示全部楼层
洋务德雷 发表于 2023-3-29 17:18
看一下这个,我这个好像代码量不大。

看的如此好的数据结构和算法,眼睛发亮。
但我试了一下几万行4列的数据,运行程序出错了,提示数组下标越界。
等下我来调试一下。

TA的精华主题

TA的得分主题

 楼主| 发表于 2023-3-29 20:19 | 显示全部楼层
[广告] Excel易用宝 - 提升Excel的操作效率 · Excel / WPS表格插件       ★免费下载 ★       ★ 使用帮助
wanghan519 发表于 2023-3-29 18:11
写了个好玩的,所有单元格写入同一个字典d,只不过value是按位或2的列数次方(列数从0开始到3),最后value为 ...

这个是wps里编的吧,这个脚本还不会,得收藏慢慢消化。

TA的精华主题

TA的得分主题

 楼主| 发表于 2023-3-29 20:25 | 显示全部楼层
micch 发表于 2023-3-29 18:42
行数不是很大的情况下,字典就是最快的方法。如果字典速度不行,可以根据数据的情况进行处理。以举例来说, ...

双循环每个数据逐一比对的算法时间复杂度高,为O(n^2),加上多列,时间复杂度为O(列数*n^2)

TA的精华主题

TA的得分主题

发表于 2023-3-29 21:17 | 显示全部楼层
[广告] Excel易用宝 - 提升Excel的操作效率 · Excel / WPS表格插件       ★免费下载 ★       ★ 使用帮助
吴中泉 发表于 2023-3-29 20:25
双循环每个数据逐一比对的算法时间复杂度高,为O(n^2),加上多列,时间复杂度为O(列数*n^2)

不需要双循环比对,字典算是循环比对,只不过字典判断速度算是比较快。

我是说,如果实际数据是数字,甚至是个位数,那根本不需要循环比对,按值处理就行。如果是个位数,只需循环10个数字,如果是两位数只需循环99次,和数据量无关

TA的精华主题

TA的得分主题

 楼主| 发表于 2023-3-29 22:33 | 显示全部楼层
洋务德雷 发表于 2023-3-29 17:18
看一下这个,我这个好像代码量不大。

我调试了一下代码,并稍加修改,通用一些,速度很快,几乎瞬间完成(200多毫秒),一万多行四列数据比我编快了3倍,我的代码耗时在排序上不少。

  1. Option Explicit

  2. Sub Main()
  3.       Dim d As Object
  4.       Dim arr, i As Long, j As Long
  5.       Dim t
  6.       arr = ActiveSheet.Range("a1").CurrentRegion
  7.       Set d = CreateObject("scripting.dictionary")
  8.       For i = 1 To UBound(arr)
  9.             d(arr(i, 1)) = 1
  10.       Next i
  11. '      Stop
  12.       For j = 2 To UBound(arr, 2)
  13.             For i = 1 To UBound(arr)
  14.                   If d.exists(arr(i, j)) Then
  15.                         d(arr(i, j)) = d(arr(i, j)) + 1
  16.                   End If
  17.             Next i
  18.       Next j

  19.       For i = 1 To UBound(arr)
  20.             If d(arr(i, 1)) < UBound(arr, 2) Then
  21.                   d.Remove (arr(i, 1))
  22.             End If
  23.       Next i
  24. '      Stop
  25.       Range("f2").Resize(d.Count, 1) = Application.Transpose(d.keys)
  26.       Erase arr
  27.       Set d = Nothing
  28. End Sub
  29. '时间复杂度:O(n+n*列数+n)
复制代码


无标题.png
image.png

但不知为什么遇到这么大的数字(上万条以上),程序出错了,是不是长数字作字典键名有问题?


TA的精华主题

TA的得分主题

 楼主| 发表于 2023-3-29 22:39 | 显示全部楼层
micch 发表于 2023-3-29 21:17
不需要双循环比对,字典算是循环比对,只不过字典判断速度算是比较快。

我是说,如果实际数据是数字, ...

嗯嗯,位数少无所谓,主要是查找很多位数(如身份证),还有文字等。

TA的精华主题

TA的得分主题

 楼主| 发表于 2023-3-30 06:50 来自手机 | 显示全部楼层
吴中泉 发表于 2023-3-29 22:33
我调试了一下代码,并稍加修改,通用一些,速度很快,几乎瞬间完成(200多毫秒),一万多行四列数据比我 ...

反复思考了一下,程序出错的原因是234等列每列中有重复数据,对这些列也要去重。

TA的精华主题

TA的得分主题

发表于 2023-3-30 07:02 | 显示全部楼层
[广告] VBA代码宝 - VBA编程加强工具 · VBA代码随查随用  · 内置多项VBA编程加强工具       ★ 免费下载 ★      ★使用手册
吴中泉 发表于 2023-3-29 22:33
我调试了一下代码,并稍加修改,通用一些,速度很快,几乎瞬间完成(200多毫秒),一万多行四列数据比我 ...

从第一列到最后一列,为啥要分两段循环,明明一次双循环即可以的

TA的精华主题

TA的得分主题

发表于 2023-3-30 08:06 来自手机 | 显示全部楼层
[广告] VBA代码宝 - VBA编程加强工具 · VBA代码随查随用  · 内置多项VBA编程加强工具       ★ 免费下载 ★      ★使用手册
吴中泉 发表于 2023-3-29 20:19
这个是wps里编的吧,这个脚本还不会,得收藏慢慢消化。

是wps写的,但思路很简单改写不难,建一个字典d,遍历每个数据作为字典的key,字典的值是一个二进制的数字,比如第一列就用这个值 或操作 1,第二列就 或2,第四列就 或8,这样只遍历一次复杂度O(n),最后只要筛出值是15(1+2+4+8=15)的就是四列都出现的

TA的精华主题

TA的得分主题

 楼主| 发表于 2023-3-30 08:12 | 显示全部楼层
zxsea_7426 发表于 2023-3-30 07:02
从第一列到最后一列,为啥要分两段循环,明明一次双循环即可以的

原作者编写的,主要考虑减少加入字典的元素,比如234列就不要加入,只要查一下以单元格数据为键名的是否在列1存在,存在就加1,说明该数据与列1中数据有重复.
您需要登录后才可以回帖 登录 | 免费注册

本版积分规则

手机版|关于我们|联系我们|ExcelHome

GMT+8, 2024-9-29 12:25 , Processed in 0.032986 second(s), 6 queries , Gzip On, MemCache On.

Powered by Discuz! X3.4

© 1999-2023 Wooffice Inc.

沪公网安备 31011702000001号 沪ICP备11019229号-2

本论坛言论纯属发表者个人意见,任何违反国家相关法律的言论,本站将协助国家相关部门追究发言者责任!     本站特聘法律顾问:李志群律师

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