前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Excel公式练习37: 找到和的加数(增强版)

Excel公式练习37: 找到和的加数(增强版)

作者头像
fanjy
发布2020-02-14 12:30:37
9210
发布2020-02-14 12:30:37
举报
文章被收录于专栏:完美Excel完美Excel

学习Excel技术,关注微信公众号:

excelperfect

导语:继续研究来自于excelxor.com的案例。在《Excel公式练习36:找到和的加数》中,讲解了一个公式,可以标出指定和的加数,然而,如果有几种组合都可以得到这个和数,该公式只能标出其中一种组合,本文讲解的公式就来解决这个问题,将所有的组合都标出来。

本次的练习是:如下图2所示,在单元格A1中给出了目标值1054.35,在单元格A2:A11中有10个值,现在我们想知道这些值中哪些值相加等于1054.35,在这些值右侧单元格中使用“X”标记。如果有几种组合加起来都等于1054.35,则将他们都标识出来。

图1

在单元格B2中输入公式,然后向下拖放至单元格B11、向右拖放至K列,得到结果。

在本例中,有3个组合:

1054.35=350.25+246.89+457.21

1054.35=290.27+123.69+198.56+201.35+240.48

1054.35=283.75+290.27+123.69+201.35+155.29

那么,如何编写这个公式呢?

先不看答案,自已动手试一试。

公式

在单元格B2中输入数组公式:

=IF(COLUMNS($A:A)>$L$1,"",IF(INDEX(INDEX(MOD(INT((Arry2-1)/2^(TRANSPOSE(Arry1)-1)),2),SMALL(IF(MMULT(MOD(INT((Arry2-1)/2^(TRANSPOSE(Arry1)-1)),2),Values)=$A$1,Arry2),COLUMNS($A:A)),),ROWS($1:1)),"X",""))

向下拖拉至单元格B11,向右拖至列K。

公式使用了一个辅助单元格L1,内容为相加等于目标值的组合的个数,其中使用的数组公式为:

=SUM(N(MMULT(MOD(INT((Arry2-1)/2^(TRANSPOSE(Arry1)-1)),2),Values)=A1))

公式解析

公式中的Values、Arry1和Arry2是定义的三个名称。

名称:Values

引用位置:=$A$2:$A$11

名称:Arry1

引用位置:=ROW(INDIRECT("1:" & ROWS(Values)))

名称:Arry2

引用位置:=ROW(INDIRECT("1:" & 2^ROWS(Values)))

下面以一个确定为和的加数的单元格中的公式,来看看公式是怎么运转的。在单元格B5中的公式为:

=IF(COLUMNS($A:A)>$L$1,"",IF(INDEX(INDEX(MOD(INT((Arry2-1)/2^(TRANSPOSE(Arry1)-1)),2),SMALL(IF(MMULT(MOD(INT((Arry2-1)/2^(TRANSPOSE(Arry1)-1)),2),Values)=$A$1,Arry2),COLUMNS($A:A)),),ROWS($1:4)),"X",""))

1. 先看看公式中的这部分:

MOD(INT((Arry2-1)/2^(TRANSPOSE(Arry1)-1)),2)

这是本解决方案的关键。上述部分公式将会生成一个1024行10列的大矩阵数组,为了更好地理解其运作原理,我们看一个生成的数组数量较小的版本。

假设数值是4个,而不是示例中的10个,即名称Values定义不是:

=$A2:$A11

而是:

=$A2:$A5

这样,名称Arry1:

=ROW(INDIRECT("1:"& ROWS(Values)))

转换为:

=ROW(INDIRECT("1:" & 4))

得到:

{1;2;3;4}

名称Arry2:

=ROW(INDIRECT("1:"& 2^ROWS(Values)))

转换为:

=ROW(INDIRECT("1:" & 2^4))

转换为:

=ROW(INDIRECT("1:" & 16))

得到:

{1;2;3;4;5;6;7;8;9;10;11;12;13;14;15;16}

这样,部分公式:

MOD(INT((Arry2-1)/2^(TRANSPOSE(Arry1)-1)),2)

转换为:

MOD(INT(({1;2;3;4;5;6;7;8;9;10;11;12;13;14;15;16}-1)/2^(TRANSPOSE({1;2;3;4})-1)),2)

转换为:

MOD(INT(({1;2;3;4;5;6;7;8;9;10;11;12;13;14;15;16}-1)/2^({0,1,2,3})),2)

转换为:

MOD(INT(({1;2;3;4;5;6;7;8;9;10;11;12;13;14;15;16}-1)/{1,2,4,8}),2)

转换为:

MOD(INT(({0;1;2;3;4;5;6;7;8;9;10;11;12;13;14;15})/{1,2,4,8}),2)

执行数组除法,因为这两个数组正交,即一个16行1列数组除以一个1行4列数组,得到一个16行4列数组:

MOD(INT(

{0,0,0,0;

1,0.5,0.25,0.125;

2,1,0.5,0.25;

3,1.5,0.75,0.375;

4,2,1,0.5;

5,2.5,1.25,0.625;

6,3,1.5,0.75;

7,3.5,1.75,0.875;

8,4,2,1;

9,4.5,2.25,1.125;

10,5,2.5,1.25;

11,5.5,2.75,1.375;

12,6,3,1.5;

13,6.5,3.25,1.625;

14,7,3.5,1.75;

15,7.5,3.75,1.875}

),2)

取整后的结果:

MOD(

{0,0,0,0;

1,0,0,0;

2,1,0,0;

3,1,0,0;

4,2,1,0;

5,2,1,0;

6,3,1,0;

7,3,1,0;

8,4,2,1;

9,4,2,1;

10,5,2,1;

11,5,2,1;

12,6,3,1;

13,6,3,1;

14,7,3,1;

15,7,3,1}

),2)

对2求余后的结果:

{0,0,0,0;

1,0,0,0;

0,1,0,0;

1,1,0,0;

0,0,1,0;

1,0,1,0;

0,1,1,0;

1,1,1,0;

0,0,0,1;

1,0,0,1;

0,1,0,1;

1,1,0,1;

0,0,1,1;

1,0,1,1;

0,1,1,1;

1,1,1,1}

可以看到,我们成功地创建了一个由0和1组成4个元素的所有16种组合。

因此,如果我们使用合适的矩阵乘法,就可以生成名称Values定义的单元格区域中数据求和的所有可能组合。例如,上面数组矩阵的第4行:

{1,1,0,0}

与假设的数据区域:

{283.75;350.25;290.27;246.89}

作为MMULT函数的参数:

=MMULT({1,1,0,0},{283.75;350.25;290.27;246.89})

得到数据区域中第1个值和第2个值之和。

又如,数组矩阵的第15行:

{0,1,1,1}

与假设的数据区域:

{283.75;350.25;290.27;246.89}

作为MMULT函数的参数:

=MMULT({0,1,1,1},{283.75;350.25;290.27;246.89})

得到数据区域中第2个值、第3个值和第4个值之和。

由于我们已经生成了所有0和1的组合,因此可以计算出数据区域内所有可能组合的和。

虽然上面讲述的是数据区域只有4个数值的情况,但它适用于其他大小的数值数量。

2. 有了上述详细讲解,我们再看看公式中的部分:

MMULT(MOD(INT((Arry2-1)/2^(TRANSPOSE(Arry1)-1)),2),Values)

将返回名称Values定义的单元格区域中数值所有可能的组合之和,组成一个1024行1列的数组,共1024个元素。下面是该数组的前50个元素:

{0;283.75;350.25;634;290.27;574.02;640.52;924.27;246.89;530.64;597.14;880.89;537.16;820.91;887.41;1171.16;457.21;740.96;807.46;1091.21;747.48;1031.23;1097.73;1381.48;704.1;987.85;1054.35;1338.1;994.37;1278.12;1344.62;1628.37;123.69;407.44;473.94;757.69;413.96;697.71;764.21;1047.96;370.58;654.33;720.83;1004.58;660.85;944.6;1011.1;1294.85;580.9;864.65;...}

上面的数组中包含等于目标值的元素(红色字体标记),还有两个是第485个和第678个元素也等于目标值。

3. 这样,公式中的部分:

MMULT(MOD(INT((Arry2-1)/2^(TRANSPOSE(Arry1)-1)),2),Values)=$A$1

实际为:

{0;283.75;350.25;634;290.27;574.02;640.52;924.27;246.89;530.64;597.14;880.89;537.16;820.91;887.41;1171.16;457.21;740.96;807.46;1091.21;747.48;1031.23;1097.73;1381.48;704.1;987.85;1054.35;1338.1;994.37;1278.12;1344.62;1628.37;123.69;407.44;473.94;757.69;413.96;697.71;764.21;1047.96;370.58;654.33;720.83;1004.58;660.85;944.6;1011.1;1294.85;580.9;864.65;...}=1054.35

比较后的结果为:

{FALSE;FALSE;FALSE;FALSE;FALSE;FALSE;FALSE;FALSE;FALSE;FALSE;FALSE;FALSE;FALSE;FALSE;FALSE;FALSE;FALSE;FALSE;FALSE;FALSE;FALSE;FALSE;FALSE;FALSE;FALSE;FALSE;TRUE;FALSE;FALSE;FALSE;FALSE;FALSE;FALSE;FALSE;FALSE;FALSE;FALSE;FALSE;FALSE;FALSE;FALSE;FALSE;FALSE;FALSE;FALSE;FALSE;FALSE;FALSE;FALSE;FALSE;...}

4. 公式中的部分:

SMALL(IF(MMULT(MOD(INT((Arry2-1)/2^(TRANSPOSE(Arry1)-1)),2),Values)=$A$1,Arry2),COLUMNS($A:A))

返回每个为TRUE的元素在数组中的位置:

SMALL(IF({FALSE;FALSE;FALSE;FALSE;FALSE;FALSE;FALSE;FALSE;FALSE;FALSE;FALSE;FALSE;FALSE;FALSE;FALSE;FALSE;FALSE;FALSE;FALSE;FALSE;FALSE;FALSE;FALSE;FALSE;FALSE;FALSE;TRUE;FALSE;FALSE;FALSE;FALSE;FALSE;FALSE;FALSE;FALSE;FALSE;FALSE;FALSE;FALSE;FALSE;FALSE;FALSE;FALSE;FALSE;FALSE;FALSE;FALSE;FALSE;FALSE;FALSE;...},{1;2;3;4;5;6;7;8;9;10;11;12;13;14;15;16;17;18;19;20;21;22;23;24;25;26;27;28;29;30;31;32;33;34;35;36;37;38;39;40;41;42;43;44;45;46;47;48;49;50;...}),1)

转换为:

SMALL({FALSE;FALSE;FALSE;FALSE;FALSE;FALSE;FALSE;FALSE;FALSE;FALSE;FALSE;FALSE;FALSE;FALSE;FALSE;FALSE;FALSE;FALSE;FALSE;FALSE;FALSE;FALSE;FALSE;FALSE;FALSE;FALSE;27;FALSE;FALSE;FALSE;FALSE;FALSE;FALSE;FALSE;FALSE;FALSE;FALSE;FALSE;FALSE;FALSE;FALSE;FALSE;FALSE;FALSE;FALSE;FALSE;FALSE;FALSE;FALSE;FALSE;...},1)

得到:

27

这告诉我们,1024个和中的第27个与我们的目标值相等。

5. 现在,我们需要返回到1024个组合的矩阵数组(即前面得到的1024行10列的矩阵),以找出这个与目标值相等的求和中涉及到的具体数值,因此,使用INDEX函数提取该矩阵数组中第27行的值:

INDEX(MOD(INT((Arry2-1)/2^(TRANSPOSE(Arry1)-1)),2),SMALL(IF(MMULT(MOD(INT((Arry2-1)/2^(TRANSPOSE(Arry1)-1)),2),Values)=$A$1,Arry2),COLUMNS($A:A)),)

转换为:

INDEX({0,0,0,0,0,0,0,0,0,0;1,0,0,0,0,0,0,0,0,0;0,1,0,0,0,0,0,0,0,0;1,1,0,0,0,0,0,0,0,0;0,0,1,0,0,0,0,0,0,0;1,0,1,0,0,0,0,0,0,0;0,1,1,0,0,0,0,0,0,0;1,1,1,0,0,0,0,0,0,0;0,0,0,1,0,0,0,0,0,0;1,0,0,1,0,0,0,0,0,0;0,1,0,1,0,0,0,0,0,0;1,1,0,1,0,0,0,0,0,0;0,0,1,1,0,0,0,0,0,0;1,0,1,1,0,0,0,0,0,0;0,1,1,1,0,0,0,0,0,0;1,1,1,1,0,0,0,0,0,0;0,0,0,0,1,0,0,0,0,0;1,0,0,0,1,0,0,0,0,0;0,1,0,0,1,0,0,0,0,0;1,1,0,0,1,0,0,0,0,0;0,0,1,0,1,0,0,0,0,0;1,0,1,0,1,0,0,0,0,0;0,1,1,0,1,0,0,0,0,0;1,1,1,0,1,0,0,0,0,0;0,0,0,1,1,0,0,0,0,0;1,0,0,1,1,0,0,0,0,0;0,1,0,1,1,0,0,0,0,0;1,1,0,1,1,0,0,0,0,0;0,0,1,1,1,0,0,0,0,0;1,0,1,1,1,0,0,0,0,0;0,1,1,1,1,0,0,0,0,0;1,1,1,1,1,0,0,0,0,0;0,0,0,0,0,1,0,0,0,0;1,0,0,0,0,1,0,0,0,0;0,1,0,0,0,1,0,0,0,0;1,1,0,0,0,1,0,0,0,0;0,0,1,0,0,1,0,0,0,0;1,0,1,0,0,1,0,0,0,0;0,1,1,0,0,1,0,0,0,0;1,1,1,0,0,1,0,0,0,0;0,0,0,1,0,1,0,0,0,0;1,0,0,1,0,1,0,0,0,0;0,1,0,1,0,1,0,0,0,0;1,1,0,1,0,1,0,0,0,0;0,0,1,1,0,1,0,0,0,0;1,0,1,1,0,1,0,0,0,0;0,1,1,1,0,1,0,0,0,0;1,1,1,1,0,1,0,0,0,0;0,0,0,0,1,1,0,0,0,0;1,0,0,0,1,1,0,0,0,0;...},27,)

结果为:

{0,1,0,1,1,0,0,0,0,0}

与单元格A3、A5和A6相对应。

6. 接下来就很简单了。只需检查所在行是否与该数组中的非零值对应:

IF(INDEX(INDEX(MOD(INT((Arry2-1)/2^(TRANSPOSE(Arry1)-1)),2),SMALL(IF(MMULT(MOD(INT((Arry2-1)/2^(TRANSPOSE(Arry1)-1)),2),Values)=$A$1,Arry2),COLUMNS($A:A)),),ROWS($1:4)),"X","")

转换为:

IF(INDEX({0,1,0,1,1,0,0,0,0,0},ROWS($1:4)),"X","")

转换为:

IF(INDEX({0,1,0,1,1,0,0,0,0,0},4),"X","")

转换为:

IF(1,"X","")

得到

X

扩展版

下面是一个修订版,具有以下功能:可以由用户指定加数的数量。如下图2所示。

图2

在图2所示的工作表中,单元格L2中的值表示只希望采用A2:A11中3个值组合之和等于目标值。可以看到,8种组合中,每种确实只有3个值。

在单元格L1中的数组公式为:

=SUM(N(MMULT(IF(MMULT(MOD(INT((Arry2-1)/2^(TRANSPOSE(Arry1)-1)),2),Arry1^0)=L2,MOD(INT((Arry2-1)/2^(TRANSPOSE(Arry1)-1)),2),0),Values)=A1))

在单元格B2中的数组公式为:

=IF(COLUMNS($A:A)>$L$1,"",IF(INDEX(INDEX(MOD(INT((Arry2-1)/2^(TRANSPOSE(Arry1)-1)),2),SMALL(IF(MMULT(IF(MMULT(MOD(INT((Arry2-1)/2^(TRANSPOSE(Arry1)-1)),2),Arry1^0)=$L$2,MOD(INT((Arry2-1)/2^(TRANSPOSE(Arry1)-1)),2),0),Values)=$A$1,Arry2),COLUMNS($A:A)),),ROWS($1:1)),"X",""))

我的脑袋已经不够用了!

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2020-02-14,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 完美Excel 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档