【问题标题】:How to loop throgh a set of rows, count.if by each row, then sum the total result?如何遍历一组行,count.if 每行,然后求和总结果?
【发布时间】:2018-01-06 03:34:36
【问题描述】:

作为我打算的等效简化示例,此工作表包含从 A 到 E 列和多行的 1-9 之间的任意 5 个数字序列:

  | 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 以更简单的方式做同样的事情。

【问题讨论】:

  • 函数Nmatch中没有定义变量Lnumber。那应该是Rnumber吗?
  • @JohnRC 是的。你是对的。编辑它。

标签: excel excel-formula vba


【解决方案1】:

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

  1. 创建一个中间矩阵,该矩阵的行数与源矩阵中的行数一样多,并且每个数字都有一列 (1 .. 9)。用公式表示对应的行是否包含列标识的数字。

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

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

这是它的外观:

中间矩阵是中间矩阵。 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 中以处理主对角线的情况:在这种情况下,单个数字必须连续出现多次才能计算后者。

您可以从Google docs下载以上表格

【讨论】:

  • 谢谢,虽然它达到了目标,但有两个问题:在我有很多数字的情况下,使用“中间”矩阵/表可能是一个问题,因为它可以改变文件的结构。并且在将数字与其自身进行比较时,您的公式会返回不希望的结果,因为两个索引条件都将指向同一列并返回其中的总和而不是行。但很容易纠正。
  • 我不确定您所说的“它可以改变文件的结构”是什么意思。将它放在另一张纸(甚至可能是隐藏的)中会解决您的问题吗?关于数字与自身的比较:我假设您指的是决赛桌中的主对角线。您的 VBA 代码省略了这种情况,所以我认为这对您来说并不重要。你想计算那个(单个)数字出现两次的行吗?
  • 想象一张包含 60000 个数字和组合的表格,正如您的有效解决方案所解释的那样,我必须构建一个全新的大表格来进行真/假验证。它仍然是一个有效的解决方案。关于主对角线,当然我确实避免了它在 VBA 代码中的计算,它在该行中明确注释:“如果 NCol = NRow Then GoTo NextN 'Skip,原因将搜索相同数字的组合。”
  • 是的,但是您还必须构建最终矩阵的结构,即 60000 行和 60000 列,对吗?关于 VBA 代码:这确实是我注意到的。所以你是说你的 VBA 代码不完整,你仍然想要主对角线的结果吗?
  • 是的,我得建两张大桌子。您的解决方案非常好,但在那种情况下,我会坚持使用 VBA 代码。而关于子“Npairs”中的VBA代码,for循环内的if条件用于检查行和列的相同数字并跳过它,从而避免在主对角线上进行不必要的计算。代码已完成并按原样运行。
【解决方案2】:

=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() 的通配符,我们可以在构建的字符串中查找数字,然后颠倒搜索顺序以捕获这两个实例。我根据结果和SUM() 构建了一个二进制数组。

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

【讨论】:

  • 这不会返回字符串中数字的相对位置的总和吗?而且由于工作表根本没有字符串,只是由其自己的单元格隔离的数字,对不起,但我没有得到使用搜索功能的意义。
  • @Musicodelic 使用搜索的要点是允许使用通配符...搜索会根据我为 5 个值的行构建的字符串中的位置返回一个数字。 ISNUMBER() 将此等同于布尔结果,用于提供 1 或 0 进行求和。您可以删除第二个 IF 语句以使顺序相对于 y,x(或第一个用于 x,y),这样表就不会表达对称性。基本上,当我想对一个数组求和时,我不能使用 Match,因为它只会提供一个结果,而单独的 IF() 不会接受通配符。
【解决方案3】:

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

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

使用命名范围将使公式更加简单。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-01-26
    • 1970-01-01
    • 2013-04-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多