Return column header based on row header and cell value

我只是一个虾纸丫 提交于 2020-01-04 09:32:25

问题


I have the following grid of data:

         ---------Header 1   Header 2   Header 3   Header 4 


Row 1       x                    x          x
Row 2                  x         x
Row 3                            x          
Row 4       x          x         x          x

I then have a second sheet that looks like this:

Row 1         Row 2        Row 3        Row 4

I would like the second sheet to end up looking like this:

    Row 1         Row 2        Row 3        Row 4
  Header 1      Header 2     Header 3     Header 1
  Header 3      Header 3                  Header 2
  Header 4                                Header 3
 .                                       Header 4                                        

Ignore that last period, I just used it to format it properly.

I've been playing with MATCH and INDEX for a couple hours and while I can get pieces of it, I can't seem to get it to all work together.

EDIT:

I use 'Header 1' and 'Row 1' as examples only. The actual data is text in Column A and Row 1, respectively. Also, since the source data will be modified, I'd prefer to have something that would automatically update the second sheet.


回答1:


Here is one way to do it with a VBA function:

In the Developer Tab(*) Click on Visual Basic, then click on the "Insert" menu there and choose "Module" to insert a new module. Then paste in the Following code:

Option Explicit

Public Function GetHeaderMatchingRow(RowText As String, _
                                    SearchRange As Range, _
                                    iHdrNo As Integer) As String
    Dim rng As Range
    Set rng = SearchRange

    Dim cel As Range

    'Get the Row to scan
    Dim i As Long, rowOff As Long
    For i = 2 To rng.Rows.Count
        Set cel = rng.Cells(i, 1)
        If cel.Value = RowText Then
            rowOff = i
            Exit For
        End If
    Next i

    'Now, scan horizontally for the iHdrNo'th non-blank cell
    Dim cnt As Integer
    For i = 2 To rng.Columns.Count
        Set cel = rng.Cells(rowOff, i)
        If Not CStr(cel.Value) = "" Then
            cnt = cnt + 1
            If cnt = iHdrNo Then
                GetHeaderMatchingRow = rng.Cells(1, i).Value
                Exit Function
            End If
        End If
    Next i

    GetHeaderMatchingRow = ""
End Function

Click on the "Debug" menu and select "Compile VBAProject".

Now go back to Excel and in your first sheet define a Named Range to cover all of your data in the grid. The Row names should be the first column in this range and the Header text should be the first row in it.

Now go to your second sheet and enter a formula like this in every output cell:

=GetHeaderMatchingRow(A$1, RowHeaderRange, 1)

Where the First parameter is the Row text that it will try to match in the first column of the range. I have "A$1" here because the in my test, my second sheet's column headers are also the Row-names in my first sheet, just like yours.

The second argument is the range to search (in this case, the Named Range we defined earlier), and the third argument is the count of the match that it is looking for (1st, 2nd, 3rd, etc.).

Note that the first and third parameters should change based on what column and row the output is for.




回答2:


Does it have to use worksheet functions? It would be quite a bit simpler to create a macro to do it (I've made an example)

Edited the function to work with row headers in col a and column headers in row 1 and changed it to read from "Source" sheet and write the result to "Output" sheet

Public Sub Example()
Dim Output As Worksheet
Dim Sheet As Worksheet
Dim Row As Integer
Dim Column As Integer
    Set Sheet = ThisWorkbook.Worksheets("Source")
    Set Output = ThisWorkbook.Worksheets("Output")
    Output.Cells.Clear ' Since were going to rebuild the whole thing, just nuke it.
    For Row = Sheet.UsedRange.Rows(Sheet.UsedRange.Rows.Count).Row To 2 Step -1
        Output.Cells(1, Row - 1).Value = Sheet.Cells(Row, 1).Value
        For Column = Sheet.UsedRange.Columns(Sheet.UsedRange.Columns.Count).Column To 1 Step -1
            If Not IsEmpty(Sheet.Cells(Row, Column)) Then
                Sheet.Cells(1, Column).Copy
                Output.Cells(2, Row - 1).Insert xlShiftDown
            End If
        Next Column
    Next Row
End Sub

I had a look at doing it with worksheet functions and as others have said its going to be pretty tricky to do it without some vba mixed in there.

If you add this to a new module then you can access it as a workbook function. (not that this is the best way to do it, just fancied having a go)

'Return The Column Header of the Nth Non-Blank Cell on Specified Row
Public Function NonBlankByIndex(ByVal Row As Integer, ByVal Index As Integer) As Range
Dim Sheet As Worksheet
Dim Column As Integer
Dim Result As Range
    Set Sheet = ThisWorkbook.Worksheets("Source") ' Change to your source sheet's name
    Set Result = Nothing
    Column = 2 ' Skip 1 as its the header
    Do
        If Column > Sheet.UsedRange.Columns(Sheet.UsedRange.Columns.Count).Column Then
            Exit Do
        End If
        If Sheet.Cells(Row, Column) = "" Then
            Column = Column + 1
        Else
            If Index = 1 Then
                Set Result = Sheet.Cells(1, Column)
                Exit Do
            Else
                Column = Column + 1
                Index = Index - 1
            End If
        End If
    Loop
    Set NonBlankByIndex = Result
End Function



回答3:


If you are happy with blanks in the listing try this in sheet2!A2:

=IF(INDEX(Sheet1!$B$2:$E$5,MATCH(A$1,Sheet1!$A$2:$A$5,0),ROW()-1)="x",INDEX(Sheet1!$B$1:$E$1,1,ROW()-1),"")

Just copy the formula over range A2:D5



来源:https://stackoverflow.com/questions/11458744/return-column-header-based-on-row-header-and-cell-value

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!