简体   繁体   中英

MS Excel: “MATCH()” does not find cells containing text if lookup array is too large

I am creating a large and complicated schedule, and I want one view which shows the schedule as a day-time grid, and another which allows one to look up a speaker by name from an alphabetical list. I have posted a simplified example here:

http://www.calpoly.edu/~epearse/excel-issue.png

In the alphabetical list, the day and time should be populated by a function using MATCH. Just as an example, I manually typed what I would like to have happen for Jones.

I cannot get MATCH() to locate the speaker's name in the timetable correctly. There are no hidden characters: notice that in cell D15, Excel correctly recognizes that G2 and C7 are identical.

Here is what happens if I put various code in H2:

  • =MATCH(G2,$A$1:$D$9) results in #N/A
  • =MATCH(G2,$C$2:$C$9) results in #N/A
  • =MATCH(G2,$B$7:$D$7) results in 2 (correctly!)
  • =MATCH(G2,$A$7:$D$7) results in #N/A

What I would like is to put =MATCH(G2,$A$1:$D$9) into H2 and then fill cells down to H25, and have Excel indicate the column number of the day in which the adjacent name appears, then use INDIRECT or something to convert this number into the day of the week.

It may be that including column A in the search array causes problems because of the different data types. As an experiment, I made the first column into TEXT, and in this case =MATCH(G2,$A$7:$D$7) incorrectly returns 1!

And even so, I cannot understand why $B$7:$D$7 works but neither $C$2:$C$9 nor $B$7:$D$8 will.

Any workarounds or alternative strategies would be greatly appreciated, thanks.

To do this you need to add in some other logic to find the correct column and row. This AGGREGATE() Function does the job.

For Day use:

=INDEX($A$1:$D$1,AGGREGATE(15,6,COLUMN($A$2:$D$9)/(($A$2:$D$9=G2)),1))

For Hour:

=INDEX($A$1:$A$9,AGGREGATE(15,6,ROW($B$1:$D$9)/(($B$1:$D$9=G2)),1))

在此处输入图片说明

The AGGREGATE() Function was introduced in Excel 2010.


For other Versions:

Pre 2010, they will need to be Array Formulas:

Day:

=INDEX($A$1:$D$1,MIN(IF($A$2:$D$9=G2,COLUMN($A$2:$D$9))))

Hour:

=INDEX($A$1:$A$9,MIN(IF($B$1:$D$9=G2,ROW($B$1:$D$9))))

Being an Array Formula it must be confirmed with Ctrl-Shift-Enter when exiting Edit mode. When done correctly Excel will automatically put {} around the formula to denote an array formula.

Newest Office 360 or online:

Day:

=INDEX($A$1:$D$1,MINIFS(COLUMN($A$2:$D$9),$A$2:$D$9,G2))

Hour:

=INDEX($A$1:$A$9,MINIFS(ROW($B$1:$D$9),$B$1:$D$9,G2))

As to the reason MATCH will not work in this case:

MATCH() only works with a single row or column and not a multiple column/row range. It is set up to return a number equal to the order place found and therefore must be a 1 dimensional array.

The most efficient way to do this given your dataset is to use three MATCH queries - one for each column.

For the Day, that looks like this:

=IF(ISERROR(MATCH(G2,$B$2:$B$10,0)),"",$B$1)&IF(ISERROR(MATCH(G2,$C$2:$C$10,0)),"",$C$1)&IF(ISERROR(MATCH(G2,$D$2:$D$10,0)),"",$D$1)

For the Time, that looks like this:

=INDEX($A$2:$A$10,IFERROR(MATCH(G2,$B$2:$B$10,0),0) + IFERROR(MATCH(G2,$C$2:$C$10,0),0) + IFERROR(MATCH(G2,$D$2:$D$10,0),0))

...but truth be told, on small datasets such as this one, you won't notice any performance difference on this approach vs Scott's AGGREGATE approach. On large datasets (thousands of rows) you probably will.

Note that another reason your initial approach failed is that you did not specify the 3rd argument of MATCH, and so Excel used the default value that assumes your list data is sorted alphabetically. You almost never want to omit that argument, and you almost always want to use FALSE (or Zero, which means FALSE to Excel)

Alternative solution with vba & listobjects (you need to give the two tables the names as appear in the code below) sheet screenshot Public Sub makeAppointmentList() Dim aSheet As Worksheet Set aSheet = 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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM