使用INDEX/MATCH进行三维查找

23

这段内容稍作修改而来,原问题已被删除

对于那些能够查看被删除的帖子的人,它取自于这里:https://stackoverflow.com/questions/39793322/three-dimensional-lookup-no-concatenate-or-named-ranges-excel


我正在尝试进行三维查找,但不使用命名范围或合并。简单来说,我的数据格式为:

    Column1 Column2 Column3
Scott           
P   1       2       3
M   4       5       6
N   7       8       9
George          
P   10      11      12
M   13      14      15
N   16      17      18

我现在想要在一个特定的名字表中搜索一个特定的字母,然后将这一行与特定的列匹配。

我尝试了简单的INDEX/MATCH函数:

=INDEX(A:D,MATCH("M",A:A,0),MATCH("Column1",1:1,0))

对于第一个名字可以这样做,但对于其他名字不行,因为它只会找到第一个 M 的实例。

我该如何修改它以查找不同的名字?


我已经回答了下面的问题,但想看看是否有更好的解决方案。


1
这取决于数据输入的可能性。如果P、M、N不总是字母(可能还有其他字符),那么就要考虑这种情况。此外,空白行是否只出现在带有名称的行上? - MacroMarc
从当前答案中可以看出已经做出了这些假设。我的答案假设它可以以任何顺序进行。唯一需要注意的是数据集的大小为4。为了最小化误报,这需要更改为最大的数据集。我正在寻找是否可以在没有任何限制的情况下完成它。所有当前的答案都有某种限制。@MacroMarc - Scott Craner
11个回答

16
你可以在第一个MATCH函数中使用其他两个INDEX/MATCH函数,以设置查找范围。然后只需添加MATCH()函数即可找到名称的绝对位置。
=INDEX(A:D,MATCH($H$4,INDEX(A:A,MATCH($H$3,A:A,0)):INDEX(A:A,MATCH($H$3,A:A,0)+4),0)+MATCH($H$3,A:A,0)-1,MATCH($H$5,$1:$1,0))

![enter image description here


这个更好的方案没有大小限制:
=INDEX(A:D,MATCH(F4,INDEX(A:A,MATCH(F3,A:A,0)):A1040000,0)+MATCH(F3,A:A,0)-1,MATCH(F5,A1:D1,0))

enter image description here


15
我使用了一个IF()语句array公式来找到在George行之后的P行号... 我还需要使用MIN()函数来获取名字后第一个P行号。
除此之外,这是一个简单的INDEX()函数.... 让我苦思冥想了一个多小时 :). =INDEX($A$1:$D$9,MIN(IF((ROW(A1:A9)>MATCH($F$4,A1:A9,0))*(A1:A9=$F$5),ROW(A1:A9),"")),MATCH($F$6,$A$1:$D$1,0)) 别忘了!
在完成公式时使用Ctrl+Shift+Enter,以便将其评估为array公式。

3 Dimensional Array Function


6

您可以通过将两个匹配的结果相加来完成此操作。一个匹配用于名称,另一个匹配用于字母,二者之和等于总行数。

=INDEX(A:D,MATCH(G5,A3:A5,0)+MATCH(G3,A:A,0),MATCH(G4,1:1,0))

换句话说:Index(所有数据,Match(名称,在名称列中,精确匹配) + Match(字母,在字母列中,精确匹配),Match(列名,在列行中,精确匹配)

工作表截图


2
如果每个名称后面的字母都以严格的一致性出现,则简单而非常好。对于严格一致的情况,这可能是最好的想法。但是在问题的评论中,Scott Craner正在尝试为更一般的情况找到公式构造,最好是在数据输入方面少做假设或限制。显然,数据集必须具有某些结构,但我认为我们不应该将其限制为完全相同的四个字母以完全相同的顺序出现。 - MacroMarc

4

我的回答尝试了一般情况,只有一个限制:

一个字母是单个字符文本,而一个名称则超过1个字符。否则,我觉得在逻辑上字母和名称之间没有区别,那么真正做到...

重新编辑以实现更好的功能构建:

{=INDEX($A$1:$D$17, MATCH($H$3,$A1:$A17, 0)+MATCH($H$4, INDEX($A1:$A17, MATCH($H$3,$A1:$A17, 0)):INDEX($A:$A, SMALL(IFERROR(MATCH($H$3,$A1:$A17, 0)+POWER(SQRT(IF(LEN($A$1:$A$17)>1, ROW($A$1:$A$17), 0)-MATCH($H$3,$A$1:$A$17, 0)), 2)-1, ROWS($A$1:$A$17)), 2)), 0)-1, MATCH($H$5, $A$1:$D$1, 0))}

这个公式使用了沿着A列的数组公式,检查长度是否大于1并将行号放入一个数组中,其中字母被赋值为0。
然后从每个唯一名称(例如George)的行中减去匹配的行。
然后我们使用min(所有其他名称行,最后一个数据行作为最终默认值-SMALL函数的2个参数)来找到下一个名称行(如果没有以下名称,则为最后一个数据行)。
其余部分是标准的index/match等。
如果所选名称下没有这样的字母,它将正确返回#N/A...

enter image description here

我的数据集是A1:A17,公式可以每次使用A:A,但IF中的数组计算需要A1:A17以提高速度。
编辑以改善函数构建:
如果我们想避免在数据长度更改时编辑公式,则可以让A:A的完整列引用通过整个构造(并失去速度/效率),其中colA中的最后一个数据行通过ROWS(A:A)进行计算。
重新编辑:
{=INDEX($A:$D, MATCH($H$3,$A:$A, 0)+MATCH($H$4, INDEX($A:$A, MATCH($H$3,$A:$A, 0)):INDEX($A:$A, SMALL(IFERROR(MATCH($H$3,$A:$A, 0)+POWER(SQRT(IF(LEN($A:$A)>1, ROW($A:$A), 0)-MATCH($H$3,$A:$A, 0)), 2)-1, ROWS($A:$A)), 2)), 0)-1, MATCH($H$5,1:1, 0))}

这取决于设置...
如果您想使用空格作为名称的分隔符,在数据结果中没有空格,但在B到D列中出现名称时有空格,则上述公式的微小更改将导致以下结果:
这意味着名称和字母不必具有任何指定长度,但只有一个条件是名称所在行中出现空格。
将寻找字母结束范围的条件进行小修改,将SQRT(IF(LEN($A$1:$A$17)>1,替换为SQRT(IF($B$1:$B$17="",

2
我会使用Index()的区域(第四个参数)。以下是测试数据的屏幕截图。此示例假定相同的列和键已排序并保持一致。
这是通过使用(Range1, Range2)作为index的第一个参数来实现的。对于index的第四个参数,请使用N,以指定你想要Index返回的区域。

enter image description here


如果区域已知且区域较少,则这是一个不错的选择。我猜可能会有多个名称,因此为每个名称添加区域并计算区域以获得正确的名称可能会变得繁琐,且需要一个很长的公式。 - Scott Craner
1
命名区域可以提供帮助,但它们的作用有限。此外,我们必须记住一切都要在现实世界中保持实用性(我们能做梦吗?)。 - Kevin

2

我认为这样可能会更整洁,也更容易修改。

=INDEX(OFFSET(INDIRECT("A"&MATCH($H$3,$A:$A,0),TRUE),0,0,4,4),MATCH($H$4,$A:$A,0),MATCH(H5,$1:$1,0))

使用偏移量来创建范围,我们可以使用H3中的名称进行设置,然后在该新范围内进行索引。现在这仍然取决于名字保持在A列中。

是的,但我倾向于避免使用OFFSET和INDIRECT函数,因为它是一种易变函数。在这种情况下,如果只有一个函数,那么问题不大,但是如果整个页面都充满了易变函数,将会拖慢计算时间。 - Scott Craner
由于第一个名称在第二行而不是第一行,因此您需要对第一个匹配进行-1的调整,否则它会显示错误的数字。=INDEX(OFFSET(INDIRECT("A"&MATCH($H$3,$A:$A,0),TRUE),0,0,4,4),MATCH($H$4,$A:$A,0)-1,MATCH(H5,$1:$1,0)) - Scott Craner
更整洁、更易修改……也许是这样,但您也涉及到了易变函数。 - user4039065
啊,好的,那很有道理。有没有易失函数列表可以参考,或者有什么记住哪些是易失的经验法则? - Jacob Edmond

2
假设数据格式始终为Name,然后是PMN,则以下公式可起到作用:
=INDEX($A:$D,
MATCH($H$3,$A:$A,0)
+LOOKUP($H$4,{"P",1;"M",2;"N",3}),
MATCH($H$5,$1:$1,0))

2

这种解决方案几乎适用于所有情况。我发现的一个限制是,当(名称)中的一个主题没有任何详细信息(字母)的数据时,但目前所有其他答案都存在该问题。

该公式假定数据位于B6:F30(以确保无论源范围位置如何,都可以应用它)。

该公式使用Index\Match函数:

首先,使用MATCH函数检索名称的位置:

MATCH($H8,$B$6:$B$30,0)

根据这些信息,它使用INDEX函数创建一个范围,用于获取第二个MATCH函数得出的Detail(字母)的位置:

+ MATCH($I8,INDEX($B$6:$B$30, 1 + MATCH($H8,$B$6:$B$30,0))
:INDEX($B$6:$B$30,ROWS($B$6:$B$30)),0),

将第一和第二个MATCH函数的结果相加,可以得到Name`Detail`组合的位置,并在整个数据中使用Index。所需数据列的位置是通过Match获得的:

INDEX($B$6:$F$30, 1st.MATCH + 2nd.MATCH,
MATCH(J$6,$B$6:$F$6,0))

结果位于 G6:L30,请在 J8 中输入此公式,然后复制到 J8:L30

= INDEX( $B$6:$F$30,
MATCH( $H8, $B$6:$B$30, 0)
+MATCH( $I8, INDEX( $B$6:$B$30 , 1 + MATCH( $H8, $B$6:$B$30 ,0))
: INDEX( $B$6:$B$30, ROWS($B$6:$B$30) ),0),
MATCH( J$6, $B$6:$F$6, 0)),"")

enter image description here


只有在所有细节都相同的情况下,这才有效。是的,顺序无关紧要,但实际细节很重要。举个例子,从数据集中去掉乔治的细节2,突然J8将会提取第16行,这会导致错误的匹配结果。你的公式与我的非常相似,我将其限制在仅有四行,以期减少错误的匹配结果。 - Scott Craner
我发现的一个限制是,当其中一个主题(名称)没有任何细节(字母)的数据时,但目前所有其他答案都是相同的。我的答案会正确地找到#N/A,如果一个名字没有这个字母(或任何字母)。 - MacroMarc
@ScottCraner 这就是为什么当其中一个主题(名称)没有任何细节(字母)的数据时,它就无法工作的原因。 - EEM
@ScottCraner 这个公式和你发布的不一样。要验证,只需在数据之前插入一列(即列 A),在两种情况下,你发布的公式将产生不准确的结果,插入三列它会生成 #REF!,而这个答案中的公式将继续显示正确的结果(除了已经解释过的例外情况)。 - EEM
@MacroMarc 很抱歉,我不得不承认你的公式返回错误,但不幸的是它只适用于细节都具有相同长度(在这种情况下为1)的情况,而在现实生活中这种情况并不经常发生。另外,如果你在数据上方添加一行,你的公式会变得不准确。 - EEM
@EEM,干得好 - 我混淆了完整列和有限范围的引用技术。我给出的第二个选项在任何情况下仍然适用,尽管我不得不重新编辑。至于数据输入的假设,它是开放的。一些情况下具有特定格式的字母/代码可以进行测试。有些是自由的,但我们没有其他约束传递给我们。这是尝试解决最一般情况的一种方法。我们需要分离出名称。空格可能足够,但我们不知道数据集中是否会有空格或零。我觉得空格可能是正确的选择。 - MacroMarc

1
这个解决方案适用于到目前为止讨论的所有情况(如果有任何不适用的情况,请告诉我,我会尽力涵盖)。我将其作为一个独立的答案发布,因为在先前的答案中应用的公式仅适用于其中所述的条件,因此它们将对具有这些特定场景的用户非常有用,因此他们不需要应用这些冗长的公式。

该公式假定数据位于B6:E30(为了确保它可以应用于任何源范围位置)

该公式使用Index\Match函数,是一个Formula Array。

FormulaArrays是通过同时按下[Ctrl]+ [Shift]+ [Enter]输入的,如果正确输入,您将看到该公式周围有{}

语法:

=IFERROR(INDEX(DataRng,
MATCH(Value1,NamesRng,0)
+IFERROR(MATCH(Value2,INDEX(NamesRng,
1+MATCH(Value1,NamesRng,0))
:INDEX(NamesRng, IFERROR(MATCH(Value1,NamesRng,0)
+MATCH("#",IF((INDEX(Col1Rng,1+MATCH(Value1,NamesRng,0))
:INDEX(Col1Rng,ROWS(NamesRng)))="","#","!"),0),
ROWS(NamesRng))),0),NA()),MATCH(ValCol,DataHdr,0)),"")
参数: 假设数据位于B6:E30。

Value1= Name,在数据中需要查找的名称,如George、Scott等。

Value2= Detail,在数据中需要查找的细节信息,如Detail1、Detalle2等。

ValCol = Column,在数据中需要查找的列,如Column1、Column2等。

DataRng= $B$6:$E$30

DataHdr= $B$6:$E$6

NamesRng= $B$6:$B$30

Col1Rng= $C$6:$C$30

第一次匹配:获取名称的位置:

MATCH(Value1,NamesRng,0)

第二个匹配:检索与姓名对应的详细信息的结束位置,该位置由列C中的空值或数据范围的末尾确定:

MATCH("#",IF((INDEX(Col1Rng, 1 + 1stMATCH)
:INDEX(Col1Rng,ROWS(NamesRng)))="","#","!"),0),

使用第一个和第二个匹配函数的名称详细信息,构建范围(vRange)。如果第二个匹配返回错误,则使用数据范围的最后一行。
INDEX(NamesRng, 1 + 1stMATCH )
:INDEX(NamesRng, IFERROR( 1stMATCH + 2ndMATCH, ROWS(NamesRng)))

第三个匹配: 检索 vRangeDetail 的位置。如果组合不存在,则返回 #NA

IFERROR(MATCH(Value2, vRange,0), NA())

将第一个和第三个匹配函数的结果相加,可以获得Name `Detail`组合的行索引,如果没有找到则返回#NA。 使用数据标题进行匹配可以获得列索引。 然后应用INDEX函数于数据范围,返回Name\Detail\Column组合的值。 如果未找到Name\Detail组合,则返回空白。

=IFERROR( INDEX( DataRng, 1stMATCH + 3rdMATCH, MATCH(Column,DataHdr,0)),"")

将结果位于H6:L37,输入此数组公式到J8,然后复制到K8:L37和J9:L37:

=IFERROR( INDEX($B$6:$E$30,
MATCH($H8,$B$6:$B$30,0)
+IFERROR( MATCH($I8, INDEX($B$6:$B$30,
1+MATCH($H8,$B$6:$B$30,0))
:INDEX($B$6:$B$30, IFERROR(MATCH($H8,$B$6:$B$30,0)
+MATCH("#", IF((INDEX($C$6:$C$30,1+MATCH($H8,$B$6:$B$30,0))
:INDEX($C$6:$C$30,ROWS($B$6:$B$30)))="","#","!"),0),
ROWS($B$6:$B$30))),0),NA()),
MATCH(J$6,$B$6:$E$6,0)), "")

enter image description here


0

当我有超过两个输入用于数据搜索时,我更喜欢将数据组织如图所示,这样我就可以使用数据透视表,并按照我喜欢的方式将数据组织成行和列。

然后我使用GETPIVOTDATA搜索值。

单元格G9包含此公式:

=GETPIVOTDATA("Value";$F$3;"Name";G15;"Letter";G16;"Column";G17)

enter image description here


如果可以重新排列数据,那么只需使用SUMIFS函数即可轻松获得数字:=SUMIFS(D:D,A:A,G15,B:B,G16,C:C,G17)。但挑战在于不改变数据结构的情况下完成此操作。 - Scott Craner

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接