ExcelHome技术论坛

 找回密码
 免费注册

QQ登录

只需一步,快速开始

快捷登录

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

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

[复制链接]

TA的精华主题

TA的得分主题

发表于 2023-3-29 14:58 | 显示全部楼层 |阅读模式
第一次发贴,新手上路,请多指教.

如题,提取任意多行多列中每列都有的重复值,数据量大速度快.这也因有坛友需要编写的,也是边学边编,肯定有更好的算法,希望大家一起讨论交流,相互提高.
image.png



  1. Sub 提取多列中每列都有的重复值()
  2. '利用排序和二分查找降低时间复杂度,提高效率
  3.     Dim arr
  4.     Dim arr1(), arr_temp()
  5.     Dim i, j, m, g, fi, max_row, max_col As Integer
  6.     'i为行下标,j为列下标,m为一个数重复次数,g为重复数的多少
  7.     'max_row为区域最大行,max_col为区域最大列
  8.     t = Timer

  9.     '复制到ss1开始的区域,并对各列(不含第1列)进行排序
  10.    
  11.     Range("a1").CurrentRegion.Copy [ss1]
  12.     Set rng = [ss1].CurrentRegion
  13.     max_row = rng.Rows.Count
  14.     max_col = rng.Columns.Count
  15.     For j = 2 To max_col
  16.         rng.Range("a1:a" & max_row).Offset(0, j - 1) _
  17.             .Sort rng.Cells(1, j), xlAscending
  18.     Next j
  19.     arr = rng '区域转成二维数组
  20.     Range("ss1").CurrentRegion.Clear '清空临时区域

  21.    '查找提取各列中都有的重复值
  22.    
  23.     For i = 1 To max_row
  24.         m = 0
  25.         For j = 2 To max_col
  26.             '利用自定义二分查找函数查找
  27.             fi = twofind(arr, j, arr(i, 1))
  28.             If fi = 1 Then  '返回1为找到相同数
  29.                 m = m + 1
  30.             Else
  31.                 Exit For '没找到退出本轮查找
  32.             End If
  33.             
  34.             If m = max_col - 1 Then
  35.                 g = g + 1 '找到各列都含有的重复值,加入数组arr1
  36.                 ReDim Preserve arr1(1 To g)
  37.                 arr1(g) = arr(i, 1)
  38.             End If
  39.         Next j
  40.     Next i
  41.     Range("h2").Resize(UBound(arr1), 1) = Application.WorksheetFunction.Transpose(arr1)
  42.     MsgBox Timer - t

  43. End Sub

  44. '2分查找是否在有序数组里,数据量大时非常快,但字母和汉字比较大小有问题
  45. Function twofind(arr, col, value) '参数:被查的二维数组,列号,要找的元素值
  46.     Dim L, R, mid As Long
  47.     L = 1: R = UBound(arr)
  48.         Do While R >= L
  49.             mid = (L + R) \ 2
  50.             If value < arr(mid, col) Or arr(mid, col) = "" Then
  51.                 R = mid - 1
  52.                 twofind = 0
  53.             ElseIf value > arr(mid, col) Then
  54.                 L = mid + 1
  55.                 twofind = 0
  56.             Else
  57.                 twofind = 1
  58.                 Exit Do
  59.             End If
  60.         Loop
  61. End Function


复制代码

以下是早前编的,在数据量大的情况下速度慢了几十倍.
  1. Sub 提取多列中每列都有的重复值()
  2.     Dim arr
  3.     Dim arr1()
  4.     Dim i, j, k, m, g As Integer
  5. 'i、k为行下标,j为列下标,m为一个数重复次数,g为重复数的多少
  6.     t = Timer
  7.     arr = Range("a1").CurrentRegion
  8.     For i = 1 To UBound(arr)
  9.         j = UBound(arr, 2)
  10.         m = 0
  11.         k = 1
  12.         Do While k <= UBound(arr)
  13.             If arr(i, 1) = arr(k, j) Then
  14.                 m = m + 1: j = j - 1: k = 0
  15.                 If j = 1 Then Exit Do
  16.             End If
  17.             k = k + 1
  18.         Loop
  19.         
  20.         If m = UBound(arr, 2) - 1 Then
  21.             g = g + 1
  22.             ReDim Preserve arr1(1 To g)
  23.             arr1(g) = arr(i, 1)
  24.         End If
  25.     Next
  26.     Range("g2").Resize(UBound(arr1), 1) = Application.WorksheetFunction.Transpose(arr1)
  27.     MsgBox Timer - t

  28. End Sub

复制代码







TA的精华主题

TA的得分主题

发表于 2023-3-29 16:38 | 显示全部楼层
只要把多列转换成单列就可以找出重复值。不用编写vba代码。

TA的精华主题

TA的得分主题

发表于 2023-3-29 16:54 | 显示全部楼层
洋务德雷 发表于 2023-3-29 16:38
只要把多列转换成单列就可以找出重复值。不用编写vba代码。

楼主要求的是每列都有的重复值。

TA的精华主题

TA的得分主题

发表于 2023-3-29 16:55 | 显示全部楼层
每列数据放入字典再用字典比对应该不会慢

TA的精华主题

TA的得分主题

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

每列都有的重复值.rar

15.99 KB, 下载次数: 27

TA的精华主题

TA的得分主题

发表于 2023-3-29 18:11 | 显示全部楼层
写了个好玩的,所有单元格写入同一个字典d,只不过value是按位或2的列数次方(列数从0开始到3),最后value为15的就是每列都出现过的...

image.png

TA的精华主题

TA的得分主题

发表于 2023-3-29 18:42 | 显示全部楼层
[广告] VBA代码宝 - VBA编程加强工具 · VBA代码随查随用  · 内置多项VBA编程加强工具       ★ 免费下载 ★      ★使用手册
行数不是很大的情况下,字典就是最快的方法。如果字典速度不行,可以根据数据的情况进行处理。以举例来说,数据都是数字,那数组循环会非常快,比字典快。

TA的精华主题

TA的得分主题

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

思路正确,代码简洁,速度很快。

TA的精华主题

TA的得分主题

 楼主| 发表于 2023-3-29 19:40 | 显示全部楼层
MyLaLaLand 发表于 2023-3-29 16:55
每列数据放入字典再用字典比对应该不会慢

这是一个好算法!
我想应该这样编:依次把每列数据(每列保证数据唯一不重)放入字典中去重,并记录重复次数,然后依次读出字典中重复次数大于等于列数的数据,就是要找的每列都有的重复值。
这样两个循环搞定,时间复杂度O(2n)
等回编写一下试试。论坛就是好,高手如云,受益匪浅。
而我前面编写的时间复杂度理论在O(nlogn+logn*列数)

TA的精华主题

TA的得分主题

发表于 2023-3-29 19:59 | 显示全部楼层
吴中泉 发表于 2023-3-29 19:40
这是一个好算法!
我想应该这样编:依次把每列数据(每列保证数据唯一不重)放入字典中去重,并记录重复 ...

你没有看我编写的vba吗?编写的就是这个思路呀
您需要登录后才可以回帖 登录 | 免费注册

本版积分规则

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

GMT+8, 2024-11-18 01:31 , Processed in 0.039392 second(s), 10 queries , Gzip On, MemCache On.

Powered by Discuz! X3.4

© 1999-2023 Wooffice Inc.

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

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

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