如何循环throgh一组行,count.if每行,然后总和总结果?

时间:2018-01-05 12:28:36

标签: excel excel-vba excel-formula vba

作为我想要的等效简化示例,这个工作表中包含5个数字的任意序列,每个数字在1-9之间,从A列到E列以及许多行:

  | A| B| C| D| E|
1 | 1| 5| 6| 8| 9|
2 | 2| 5| 7| 8| 9|
...
50| 1| 3| 4| 6| 7|

然后我想检查所有行中每行出现的任意两个数字的组合数,并用结果填充组合数组:

  | 1| 2| 3| 4| 5| 6| 7| 8| 9|
 1|  |  |  |  |  |  |  |  |  |
 2|  |  |  |  |  |  |  |  |  |
 3|  |  |  |  |  |  |  |  |  |
 4|  |  |  |  |  |  |  |  |  |
 5|  |  |  | x|  |  |  |  |  |
 6|  |  |  |  |  |  |  |  |  |
 7|  |  |  |  |  |  |  |  |  |
 8|  |  |  |  |  |  |  |  |  |
 9|  |  |  |  |  |  |  |  |  |

在上面,“x”表示数字4和5的组合中出现的行数。

我通过VBA代码轻松实现了我的目标,但想通过excel-formula知道如何做到这一点,因为它通常会更快。

以防任何人想要检查已经适用于此任务的VBA代码:

Sub NPairs()
Dim Rn As Long
Dim Cn As Long

For Nrow = 2 To 10
    For Ncol = 2 To 10
        If NCol = NRow Then GoTo NextN 'Skip, cause would search the combination of the same numbers.

        Rn = Plan2.Cells(NRow, 1).Value2
        Cn = Plan2.Cells(1, NCol).Value2

        Plan2.Cells(Nrow, Ncol) = NMatch(Rn, Cn)
NextN:
    Next
Next

End Sub

Private Function Nmatch(Rnumber As Long, Cnumber As Long) As Long
Lastrow = Plan1.Cells(Plan1.Rows.Count, "A").End(xlUp).Row
M = 0
For R = 2 To Lastrow
    For C = 1 To 5

        If Plan1.Cells(R, C).Value2 = Rnumber Then
            For Cl = 1 To 5
                If Plan1.Cells(R, Cl).Value2 = Cnumber Then M = M + 1
            Next
        End If

    Next
Next

Nmatch = M
End Function

我知道,这可以通过使用数组或字典来固定。我想知道的是,如果可以通过excel-formula以更简单的方式做同样的事情。

3 个答案:

答案 0 :(得分:3)

如果您关心的是速度,那么在这种情况下VBA可能会更快。但是这里有一个想法只用公式来做:

  1. 创建一个中间矩阵,其中包含与源矩阵一样多的行,并为每个数字创建一列(1 .. 9)。使用公式指示相应的行是否包含列标识的数字。

  2. 根据此中间矩阵,查找两个感兴趣的数字为TRUE的行。

  3. 如果需要,您可以隐藏中间矩阵。

  4. 以下是它的外观:

    enter image description here

    中间矩阵是中间矩阵。 G2中的公式为:

    =COUNTIF($A2:$E2, G$1)
    

    您可以将其复制到该矩阵的其他单元格

    最右边的矩阵是最终结果。 R2中的公式为:

    =IF(R$1=$Q2, COUNTIFS(INDEX($G$2:$O$9, 0, R$1),">1"), 
                 COUNTIFS(INDEX($G$2:$O$9, 0, R$1),">0", INDEX($G$2:$O$9, 0, $Q2), ">0"))
    

    INDEX函数用于检索中间矩阵中的相应列。基于当前行(在最终矩阵中)选择中间矩阵中的一列,而另一列基于当前列。两者必须具有值TRUE(在同一行中)才能计算。

    在您发表评论之后,我将公式包装在IF中以处理主对角线的情况:在这种情况下,单个数字必须连续多次出现才能计算后者。< / p>

    您可以从Google docs

    下载上述表格

答案 1 :(得分:0)

=SUM(IF(ISNUMBER(SEARCH("*"&J$1&"*"&$I2&"*",$A$1:$A$50&$B$1:$B$50&$C$1:$C$50&$D$1:$D$50&$E$1:$E$50)),1,IF(ISNUMBER(SEARCH("*"&$I2&"*"&J$1&"*",$A$1:$A$50&$B$1:$B$50&$C$1:$C$50&$D$1:$D$50&$E$1:$E$50)),1,0)))

这是一个数组公式,同时仍在公式栏中按 Ctrl + Shift + Enter

使用带有SEARCH()的通配符,我们可以查找构建字符串中的数字,然后反转serach顺序以捕获这两个实例。我根据结果构建了一个二进制数组,并SUM()

*等同于任意数量的任何字符(也可以是0个字符)。使用这个我们可以确定2个数字是否出现在5个位置的任何位置,然后翻转以捕获它们是否处于其他顺序。

enter image description here

答案 2 :(得分:0)

使用与@trincot类似的方法,使用中间表,但此表将是十列,其中包含来自源表的十对数字的集合:

enter image description here

然后使用Countif()在单独的表中计算对的出现次数:

enter image description here

使用命名范围可以使公式更简单。