比较excel中的两个范围(不要线性比较)

我在Excel中有两个范围。

样本数据

我需要执行以下操作:

1)。 计算除了零之外,我有多less个相等的值。 在我的例子中,它应该是2(1和8)。 我发现这个公式: SUMPRODUCT(--(A2:E2=A3:E3)) ,但它只会匹配B1,B2,忽略8号出现两次。

2)。 另外,我需要在单个单元格中使用逗号分隔这些重复值,就像“1,8”一样。

试试这个简单的UDF()

 Public Function compare(r1 As Range, r2 As Range) As Long Dim r As Range, v As Variant, v2 As Variant Dim rr As Range For Each r In r1 v = r.Value If v <> 0 And v <> "" Then For Each rr In r2 v2 = rr.Value If v = v2 Then compare = compare + 1 Next rr End If Next r End Function 

在这里输入图像描述

用户定义的函数(UDF)非常易于安装和使用:

  1. ALT-F11调出VBE窗口
  2. ALT-I ALT-M打开一个新的模块
  3. 粘贴东西,closuresVBE窗口

如果保存工作簿,则UDF将随之保存。 如果您在2003年以后使用的是Excel版本,则必须将该文件另存为.xlsm而不是.xlsx

要删除UDF:

  1. 如上所示调出VBE窗口
  2. 清除代码
  3. closuresVBE窗口

从Excel中使用UDF:

= myfunction的(A1)

要了解有关macros的更多信息,请参阅:

http://www.mvps.org/dmcritchie/excel/getstarted.htm

http://msdn.microsoft.com/en-us/library/ee814735(v=office.14).aspx

有关UDF的具体信息,请参阅:

http://www.cpearson.com/excel/WritingFunctionsInVBA.aspx

macros必须启用这个工作!

注意:

如果在第二个范围内有4个 QWERTY ,你会得到每个人的计数。 (但是轻微的mod可以避免这个)

这个例程将返回CSV

 Public Function compare2(r1 As Range, r2 As Range) As String Dim r As Range, v As Variant, v2 As Variant Dim rr As Range For Each r In r1 v = r.Value If v <> 0 And v <> "" Then For Each rr In r2 v2 = rr.Value If v = v2 Then compare2 = compare2 & "," & CStr(v) Next rr End If Next r If compare2 <> "" Then compare2 = Mid(compare2, 2) End Function 

在COUNTIFSarray¹公式上试试这个SUM ,

 =SUM(COUNTIFS(A2:E2, "<>"&0, A2:E2, A3:E3)) 

sum_over_countifs_array

¹ 数组公式需要使用Ctrl + Shift + Enter 来完成。 一旦正确input第一个单元格,就可以像任何其他公式一样向下或向右填充或复制它们。 尝试和减less您的全列引用范围更接近代表实际数据的范围。 数组公式将计算周期对数化,所以最好将参考范围缩小到最小。 有关更多信息,请参阅数组公式的示例 。

对于你的问题的后半部分,我将提供这个基本的UDF,它将匹配的值串在一起。 作为编程爱好者,您应该非常乐意修改代码以包含频率计数。

 Function stringMatches(rng1 As Range, rng2 As Range, _ Optional sDELIM As String = ", ", _ Optional bNOZERO As Boolean = True) Dim sTMP As String, rng As Range stringMatches = vbNullString For Each rng In rng1 If (CBool(Application.CountIf(rng2, rng.Value)) And Not bNOZERO) Or _ (CBool(Application.CountIfs(rng2, "<>" & 0, rng2, rng.Value)) And bNOZERO) Then sTMP = sTMP & rng.Value & sDELIM End If Next rng If CBool(Len(sTMP)) Then _ stringMatches = Left(sTMP, Len(sTMP) - Len(sDELIM)) End Function 

stringMatches

只需使用这个(非数组)公式:

 =SUMPRODUCT((COUNTIFS(A2:E2,"<>0",A2:E2,A3:E3)>0)*1) 

但对于第二部分,我不认为没有VBA的dynamic方式:/

作为UDF我build议这样的事情:(仅为第二部分)

 Public Function getDoubles(rng1 As Range, rng2 As Range) As String Dim cell As Variant, str As String For Each cell In rng1.Value If cell <> 0 And Not IsError(Application.Match(cell, rng2, 0)) Then str = str & cell & ", " Next getDoubles = Left(str, Len(str) - 2) End Function 

但请记住:在一个范围内多次获得一个值,公式/ UDF几乎可能会混乱

要做到这一点干净的方式(跳过所有双打),你可以使用这个:

 Public Function getDoubles(rng1 As Range, rng2 As Range, Optional getList As Boolean, Optional compType As VbCompareMethod = vbTextCompare) As Variant If rng1.Count = 1 Then getDoubles = Not IsError(Application.Match(rng1.Value, rng2, 0)) Exit Function ElseIf rng2.Count = 1 Then getDoubles = Not IsError(Application.Match(rng2.Value, rng1, 0)) Exit Function End If Dim tempCol As New Collection Dim colItem As Variant Dim isInCol As Boolean Dim rngItem As Variant For each rngItem in rng1.Value isInCol = False If Len(rngItem) > 0 And rngItem <> 0 Then 'remove the "And getOut <> 0" to do it also for 0's For Each colItem In tempCol isInCol = (StrComp(colItem, rngItem, compType) = 0) If isInCol Then Exit For Next If Not isInCol Then tempCol.Add rngItem End If Next Dim getOut As Variant If getList Then getOut = "" Else getOut = 0 End If For Each colItem In tempCol For Each rngItem In rng2 If StrComp(colItem, rngItem, compType) = 0 Then If getList Then getOut = getOut & colItem & ", " Else getOut = getOut + 1 End If Exit For End If Next Next If getList Then getDoubles = Left(getOut, Len(getOut) - 2) Else getDoubles = getOut End If End Function 

如果一个(或两个)范围只有一个项目,则它将在其他范围内返回true,否则将为false。

有2个至less2个单元格的范围,它将输出作为folows没有双打:

 =getDoubles(range1,range2) = the count of matches =getDoubles(range1,range2,1) = the "," separated list of matches =getDoubles(range1,range2,0,0) = like the first but case sensitive =getDoubles(range1,range2,1,0) = like the second but case sensitive