MS Excel:如果查找数组太大,"MATCH()" 找不到包含文本的单元格
MS Excel: "MATCH()" does not find cells containing text if lookup array is too large
我正在创建一个庞大而复杂的日程表,我想要一个将日程表显示为白天网格的视图,另一个视图允许人们从按字母顺序排列的列表中按姓名查找发言人。我在这里发布了一个简化的例子:
在按字母顺序排列的列表中,日期和时间应由使用 MATCH 的函数填充。举个例子,我手动输入了我希望琼斯发生的事情。
我无法让 MATCH() 在时间表中正确定位演讲者姓名。没有隐藏字符:请注意,在单元格 D15 中,Excel 正确识别出 G2 和 C7 是相同的。
如果我在 H2 中放入各种代码,会发生以下情况:
- =MATCH(G2,$A$1:$D$9) 结果为#N/A
- =MATCH(G2,$C$2:$C$9) 结果为#N/A
- =MATCH(G2,$B$7:$D$7) 结果为 2(正确!)
- =MATCH(G2,$A$7:$D$7) 结果为#N/A
我想要的是将 =MATCH(G2,$A$1:$D$9) 放入 H2,然后将单元格填充到 H25,并让 Excel 指示当天的列号相邻名称出现的位置,然后使用 INDIRECT 或其他方式将此数字转换为星期几。
可能是由于数据类型不同,在搜索数组中包含列 A 导致出现问题。作为实验,我将第一列设为 TEXT,在本例中 =MATCH(G2,$A$7:$D$7) 错误 returns 1!
即便如此,我还是无法理解为什么 $B$7:$D$7 有效,但 $C$2:$C$9 和 $B$7:$D$8 都无效。
任何解决方法或替代策略将不胜感激,谢谢。
为此,您需要添加一些其他逻辑来找到正确的列和行。这个 AGGREGATE() 函数可以完成这项工作。
白天使用:
=INDEX($A:$D,AGGREGATE(15,6,COLUMN($A:$D)/(($A:$D=G2)),1))
小时:
=INDEX($A:$A,AGGREGATE(15,6,ROW($B:$D)/(($B:$D=G2)),1))
AGGREGATE() 函数于 Excel 2010 年引入。
其他版本:
2010 年之前,它们需要是数组公式:
天:
=INDEX($A:$D,MIN(IF($A:$D=G2,COLUMN($A:$D))))
小时:
=INDEX($A:$A,MIN(IF($B:$D=G2,ROW($B:$D))))
作为数组公式,退出编辑模式时必须使用 Ctrl-Shift-Enter 确认。正确完成后 Excel 会自动将 {} 放在公式周围以表示数组公式。
最新的 Office 360 或在线:
天:
=INDEX($A:$D,MINIFS(COLUMN($A:$D),$A:$D,G2))
小时:
=INDEX($A:$A,MINIFS(ROW($B:$D),$B:$D,G2))
至于 MATCH 在这种情况下不起作用的原因:
MATCH() 仅适用于单个行或列,不适用于多个 column/row 范围。它被设置为 return 一个等于找到的订单位置的数字,因此必须是一维数组。
根据您的数据集执行此操作的最有效方法是使用三个 MATCH 查询 - 每个列一个。
今天,看起来像这样:
=IF(ISERROR(MATCH(G2,$B:$B,0)),"",$B)&IF(ISERROR(MATCH(G2,$C:$C,0)),"",$C)&IF(ISERROR(MATCH(G2,$D:$D,0)),"",$D)
就时间而言,它看起来像这样:
=INDEX($A:$A,IFERROR(MATCH(G2,$B:$B,0),0) + IFERROR(MATCH(G2,$C:$C,0),0) + IFERROR(MATCH(G2,$D:$D,0),0))
...但说实话,在像这个这样的小数据集上,您不会注意到这种方法与 Scott 的 AGGREGATE 方法有任何性能差异。在大型数据集(数千行)上,您可能会。
请注意,您的初始方法失败的另一个原因是您没有指定 MATCH 的第三个参数,因此 Excel 使用了假定列表数据按字母顺序排序的默认值。您几乎永远不想省略该参数,并且几乎总是想使用 FALSE(或零,这意味着 Excel 为 FALSE)
使用 vba 和 listobjects 的替代解决方案(您需要为两个表指定下面代码中显示的名称)
sheet screenshot
Public 子 makeAppointmentList()
将工作表调暗为工作表
设置工作表 = ThisWorkbook.Worksheets("sheet1")
Dim aSchedule As ListObject
Set aSchedule = aSheet.ListObjects("schedule")
Dim anAppointmentList As ListObject
Set anAppointmentList = aSheet.ListObjects("appointmentList")
On Error Resume Next
anAppointmentList.DataBodyRange.Delete
On Error GoTo 0
Dim c As ListColumn
Dim r As ListRow
Dim newRow As ListRow
For Each c In aSchedule.ListColumns
For Each r In aSchedule.ListRows
If c.Index > 1 And Intersect(c.Range, r.Range) <> "" Then
Set newRow = anAppointmentList.ListRows.Add
Intersect(newRow.Range, anAppointmentList.ListColumns("Name").Range).Value = Intersect(c.Range, r.Range)
Intersect(newRow.Range, anAppointmentList.ListColumns("Day").Range).Value = Intersect(c.Range, aSchedule.HeaderRowRange)
Intersect(newRow.Range, anAppointmentList.ListColumns("Time").Range).Value = Intersect(aSchedule.ListColumns(1).Range, r.Range)
End If
Next r
Next c
anAppointmentList.Sort.SortFields.Clear
anAppointmentList.Sort.SortFields.Add Key:=Intersect(anAppointmentList.HeaderRowRange, _
anAppointmentList.ListColumns("Name").Range)
anAppointmentList.Sort.SortFields.Add Key:=Intersect(anAppointmentList.HeaderRowRange, _
anAppointmentList.ListColumns("Day").Range), _
CustomOrder:="Mon,Tue,Wed,Thu,Fri,Sat,Sun"
anAppointmentList.Sort.SortFields.Add Key:=Intersect(anAppointmentList.HeaderRowRange, _
anAppointmentList.ListColumns("Time").Range)
anAppointmentList.Sort.Apply
Dim s As SortField
End Sub
我正在创建一个庞大而复杂的日程表,我想要一个将日程表显示为白天网格的视图,另一个视图允许人们从按字母顺序排列的列表中按姓名查找发言人。我在这里发布了一个简化的例子:
在按字母顺序排列的列表中,日期和时间应由使用 MATCH 的函数填充。举个例子,我手动输入了我希望琼斯发生的事情。
我无法让 MATCH() 在时间表中正确定位演讲者姓名。没有隐藏字符:请注意,在单元格 D15 中,Excel 正确识别出 G2 和 C7 是相同的。
如果我在 H2 中放入各种代码,会发生以下情况:
- =MATCH(G2,$A$1:$D$9) 结果为#N/A
- =MATCH(G2,$C$2:$C$9) 结果为#N/A
- =MATCH(G2,$B$7:$D$7) 结果为 2(正确!)
- =MATCH(G2,$A$7:$D$7) 结果为#N/A
我想要的是将 =MATCH(G2,$A$1:$D$9) 放入 H2,然后将单元格填充到 H25,并让 Excel 指示当天的列号相邻名称出现的位置,然后使用 INDIRECT 或其他方式将此数字转换为星期几。
可能是由于数据类型不同,在搜索数组中包含列 A 导致出现问题。作为实验,我将第一列设为 TEXT,在本例中 =MATCH(G2,$A$7:$D$7) 错误 returns 1!
即便如此,我还是无法理解为什么 $B$7:$D$7 有效,但 $C$2:$C$9 和 $B$7:$D$8 都无效。
任何解决方法或替代策略将不胜感激,谢谢。
为此,您需要添加一些其他逻辑来找到正确的列和行。这个 AGGREGATE() 函数可以完成这项工作。
白天使用:
=INDEX($A:$D,AGGREGATE(15,6,COLUMN($A:$D)/(($A:$D=G2)),1))
小时:
=INDEX($A:$A,AGGREGATE(15,6,ROW($B:$D)/(($B:$D=G2)),1))
AGGREGATE() 函数于 Excel 2010 年引入。
其他版本:
2010 年之前,它们需要是数组公式:
天:
=INDEX($A:$D,MIN(IF($A:$D=G2,COLUMN($A:$D))))
小时:
=INDEX($A:$A,MIN(IF($B:$D=G2,ROW($B:$D))))
作为数组公式,退出编辑模式时必须使用 Ctrl-Shift-Enter 确认。正确完成后 Excel 会自动将 {} 放在公式周围以表示数组公式。
最新的 Office 360 或在线:
天:
=INDEX($A:$D,MINIFS(COLUMN($A:$D),$A:$D,G2))
小时:
=INDEX($A:$A,MINIFS(ROW($B:$D),$B:$D,G2))
至于 MATCH 在这种情况下不起作用的原因:
MATCH() 仅适用于单个行或列,不适用于多个 column/row 范围。它被设置为 return 一个等于找到的订单位置的数字,因此必须是一维数组。
根据您的数据集执行此操作的最有效方法是使用三个 MATCH 查询 - 每个列一个。
今天,看起来像这样:
=IF(ISERROR(MATCH(G2,$B:$B,0)),"",$B)&IF(ISERROR(MATCH(G2,$C:$C,0)),"",$C)&IF(ISERROR(MATCH(G2,$D:$D,0)),"",$D)
就时间而言,它看起来像这样:
=INDEX($A:$A,IFERROR(MATCH(G2,$B:$B,0),0) + IFERROR(MATCH(G2,$C:$C,0),0) + IFERROR(MATCH(G2,$D:$D,0),0))
...但说实话,在像这个这样的小数据集上,您不会注意到这种方法与 Scott 的 AGGREGATE 方法有任何性能差异。在大型数据集(数千行)上,您可能会。
请注意,您的初始方法失败的另一个原因是您没有指定 MATCH 的第三个参数,因此 Excel 使用了假定列表数据按字母顺序排序的默认值。您几乎永远不想省略该参数,并且几乎总是想使用 FALSE(或零,这意味着 Excel 为 FALSE)
使用 vba 和 listobjects 的替代解决方案(您需要为两个表指定下面代码中显示的名称) sheet screenshot Public 子 makeAppointmentList() 将工作表调暗为工作表 设置工作表 = ThisWorkbook.Worksheets("sheet1")
Dim aSchedule As ListObject
Set aSchedule = aSheet.ListObjects("schedule")
Dim anAppointmentList As ListObject
Set anAppointmentList = aSheet.ListObjects("appointmentList")
On Error Resume Next
anAppointmentList.DataBodyRange.Delete
On Error GoTo 0
Dim c As ListColumn
Dim r As ListRow
Dim newRow As ListRow
For Each c In aSchedule.ListColumns
For Each r In aSchedule.ListRows
If c.Index > 1 And Intersect(c.Range, r.Range) <> "" Then
Set newRow = anAppointmentList.ListRows.Add
Intersect(newRow.Range, anAppointmentList.ListColumns("Name").Range).Value = Intersect(c.Range, r.Range)
Intersect(newRow.Range, anAppointmentList.ListColumns("Day").Range).Value = Intersect(c.Range, aSchedule.HeaderRowRange)
Intersect(newRow.Range, anAppointmentList.ListColumns("Time").Range).Value = Intersect(aSchedule.ListColumns(1).Range, r.Range)
End If
Next r
Next c
anAppointmentList.Sort.SortFields.Clear
anAppointmentList.Sort.SortFields.Add Key:=Intersect(anAppointmentList.HeaderRowRange, _
anAppointmentList.ListColumns("Name").Range)
anAppointmentList.Sort.SortFields.Add Key:=Intersect(anAppointmentList.HeaderRowRange, _
anAppointmentList.ListColumns("Day").Range), _
CustomOrder:="Mon,Tue,Wed,Thu,Fri,Sat,Sun"
anAppointmentList.Sort.SortFields.Add Key:=Intersect(anAppointmentList.HeaderRowRange, _
anAppointmentList.ListColumns("Time").Range)
anAppointmentList.Sort.Apply
Dim s As SortField
End Sub