如何将一个列的工作表1的所有值与另一个具有不同工作表2的列值进行比较,如果匹配则将与工作表1的一列相对应的值返回到另一列工作表-2在excel?
答案 0 :(得分:0)
假设您的值位于名为Sheet1
和Sheet2
的工作表的A列中。然后,您可以将以下公式放入B1
的{{1}}中并向下拖动以覆盖您所需的范围:Sheet2
或者,如果您更喜欢使用VBA,请将此代码放入模块中:
=IF(Sheet1!A1=Sheet2!A1,Sheet2!A1,"")
答案 1 :(得分:0)
答案 2 :(得分:0)
我只能回答部分问题:比较两列并检测到它们不同。
在Tony M上面的答案中,你有一个很好的教程答案。
但是,这对大型数据集执行速度非常慢,因为:
var = Range("A1")
获取单个单元所花费的时间相同,因为它使用var = Range("A1:Z1024")
一次性获取整个范围;并且与工作表的每次交互所花费的时间是VBA中字符串比较的四倍,并且比浮点小数之间的比较长二十倍;反过来,它比整数比较长三倍。
因此,如果您一次性读取整个范围,并且在VBA中处理Range.Value2
数组,那么您的代码可能快四倍,可能快一百倍。
这是Office 2010和2013(我对它们进行了测试);对于旧版本的Excel,您将看到引用时间介于1/50 th 和1/500 th 之间,对于每个VBA与单元格或范围的交互细胞。因为在旧版本和新版本的Excel中,VBA操作仍然是一位数的微秒数,所以这样会慢一点:你的代码运行速度至少要快一百倍,可能要运行数千次更快,如果你避免在旧版本的Excel中从工作表中逐个单元格读取。
如此大的收益 - 用户可感知的间隔 - 在单个“点击”中获取范围,然后在VBA中对阵列的每个项目执行比较。
arr1 = Range1.Values
arr2 = Range2.Values
' Consider checking that the two ranges are the same size
For i = LBound(arr1, 1) To Ubound(arr1, 2)
For j = LBound(arr1, 2) To Ubound(arr1, 2)
If arr1(i, j) <> arr2(i, j) Then
bMatchFail = True
Exit For
End If
Next j
If bMatchFail Then Exit For
Next i
Erase arr1
Erase arr2
您会注意到此代码示例是通用的,适用于从任何位置获取的相同大小的两个范围 - 甚至来自单独的工作簿。如果您要比较两个相邻列,则加载一个包含两列的数组并比较IF arrX(i, 1) <> arrX(i,2) Then
将使运行时减半。
如果您从大范围内获取数以万计的数值,那么您的下一个挑战才有意义:对于任何小于此范围的数据,此扩展答案都没有性能提升。
我们正在做的是:
这个想法很简单,虽然基础数学对于非数学家来说非常具有挑战性:我们不是一次比较一个值,而是运行一个数学函数,将值“散列”为一个简短的标识符,以便于比较。 / p>
如果您要将范围与“参考”副本进行比较,则可以存储“引用”哈希值,这会将工作量减半。
有一些快速可靠的散列函数,它们在Windows中作为安全和加密API的一部分提供。它们运行在字符串上有一个小问题,我们有一个数组可以工作;但您可以轻松找到一个快速的“Join2D”函数,该函数从范围的.Value2
属性返回的2D数组中获取字符串。
因此,两个大范围的快速比较函数将如下所示:
Public Function RangeCompare(Range1 as Excel.Range, Range2 As Excel.Range) AS Boolean
' Returns TRUE if the ranges are identical.
' This function is case-sensitive.
' For ranges with fewer than ~1000 cells, cell-by-cell comparison is faster
' WARNING: This function will fail if your range contains error values.
RangeCompare = False
If Range1.Cells.Count <> Range2.Cells.Count Then
RangeCompare = False
ElseIf Range1.Cells.Count = 1 then
RangeCompare = Range1.Value2 = Range2.Value2
Else
RangeCompare = MD5(Join2D(Range1.Value2)) = MD5(Join2D(Range2.Value2))
Endif
End Function
我在这个VBA函数中包装了Windows System.Security MD5哈希:
Public Function MD5(arrBytes() As Byte) As String
' Return an MD5 hash for any string
' Author: Nigel Heffernan Excellerando.Blogspot.com
' Note the type pun: you can pass in a string, there's no type conversion or cast
' because a string is stored as a Byte array and VBA recognises this.
oMD5 As Object 'Set a reference to mscorlib 4.0 to use early binding
Dim HashBytes() As Byte
Dim i As Integer
Set oMD5 = CreateObject("System.Security.Cryptography.MD5CryptoServiceProvider")
HashBytes = oMD5.ComputeHash_2((arrBytes))
For i = LBound(HashBytes) To UBound(HashBytes)
MD5 = MD5 & Right("00" & Hex(HashBytes(i)), 2)
Next i
Set oMD5 = Nothing ' if you're doing this repeatedly, declare at module level and persist
Erase HashBytes
End Function
还有其他VBA实现,但似乎没有人知道字节数组/字符串类型双关语 - 它们不是等价,它们相同 - 所以每个人都编码不必要类型转换。
2015年快速而简单的Join2D功能为posted by Dick Kusleika on Daily Dose of Excel:
Public Function Join2D(ByVal vArray As Variant, Optional ByVal sWordDelim As String = " ", Optional ByVal sLineDelim As String = vbNewLine) As String
Dim i As Long, j As Long
Dim aReturn() As String
Dim aLine() As String
ReDim aReturn(LBound(vArray, 1) To UBound(vArray, 1))
ReDim aLine(LBound(vArray, 2) To UBound(vArray, 2))
For i = LBound(vArray, 1) To UBound(vArray, 1)
For j = LBound(vArray, 2) To UBound(vArray, 2)
'Put the current line into a 1d array
aLine(j) = vArray(i, j)
Next j
'Join the current line into a 1d array
aReturn(i) = Join(aLine, sWordDelim)
Next i
Join2D = Join(aReturn, sLineDelim)
End Function
如果您需要在进行比较之前删除空白行,则需要Join2D function I posted in StackOverflow back in 2012。
此类哈希比较最常见的应用是电子表格控件 - 更改监控 - 您会看到使用Range1.Formula
代替Range1.Value2
:但您的问题是关于比较价值而不是公式。