我需要计算一个仅包含一个单元格的范围。该单元格来自最后一行和第一列。如果工作表为空,则范围为A1:A1
。
我知道有很多方法可以计算最后一行,但是我正在寻找一种优雅的方法来获取最后一行的第一行。也许有些例子可以更好地解释。
示例1
A B C D
1
2 X
3 X
4 X
结果#1
Range = A4:A4
示例2
A B C D
1
结果#2
Range = A1:A1
该怎么做?
答案 0 :(得分:0)
如果我正确理解,则希望找到某个范围(或一堆列)中的最后一行。
一种实现此目的的方法可能是循环遍历该范围内的每一列,找到最后一个单元格(在该特定列中)的哪一行,并检查它是否超过了循环中迄今为止最大的最后一行。
在下面的代码中,如果将"Sheet1"
更改为工作表调用的名称,并将范围从"A4:Z5"
更改为"A:Z"
或"A1:D4"
(或其他任何名称) (以您的情况为准),然后应显示您要查找的单元格的地址。
Option Explicit
Private Sub ShowLastCell()
' Change this to what your sheet is called.
With ThisWorkbook.Worksheets("Sheet1")
' Change this to the range you need to check.
With .Range("A4:Z5")
Dim firstColumnToCheck As Long
firstColumnToCheck = .Columns(1).Column
Dim lastColumnToCheck As Long
lastColumnToCheck = .Columns(.Columns.Count).Column
End With
Dim maxLastRow As Long
Dim columnIndex As Long
For columnIndex = firstColumnToCheck To lastColumnToCheck
maxLastRow = Application.Max(maxLastRow, .Cells(.Rows.Count, columnIndex).End(xlUp).Row)
Next columnIndex
MsgBox ("I think the cell you want is " & .Cells(maxLastRow, "A").Address & ":" & .Cells(maxLastRow, "A").Address)
End With
End Sub
答案 1 :(得分:0)
GetFirstCellInLastLine 将返回所引用工作表最后一行中的第一个单元格作为Range对象。然后,您可以使用它来做您想做的事情。例如,打印到活动工作表的“立即窗口”:
Debug.Print GetFirstCellInLastLine(ActiveSheet).Address
如果工作表为空白,则设置为返回注意,但是您可以根据需要进行修改:
'''
''' Returns the first used cell in the last line of the worksheet.
''' Returns "Nothing" if the worksheet is blank.
'''
Public Function GetFirstCellInLastLine(ws As Excel.Worksheet) As Excel.Range
Dim rng As Excel.Range
Set rng = ws.UsedRange.Cells(ws.UsedRange.Rows.Count, 1)
If ((ws.UsedRange.Columns.Count > 1) And ws.Range(rng, rng.End(xlToRight)).Columns.Count <= ws.UsedRange.Columns.Count) Then
Set rng = ws.Range(rng, rng.End(xlToRight))
If VBA.IsEmpty(rng.Cells(1, 1)) Then
Set rng = rng.Cells(1, rng.Columns.Count)
Else
Set rng = rng.Cells(1, 1)
End If
ElseIf (ws.UsedRange.Columns.Count = 1) And VBA.IsEmpty(rng.Cells(1, 1)) Then
Set rng = Nothing
End If
Set GetFirstCellInLastLine = rng
End Function
答案 2 :(得分:0)
一种优雅的方法是使用 UsedRange 属性。
'*******************************************************************************
' Purpose: Using the UsedRange Property, creates a reference to the cell *
' range at the intersection of the last used row and a specified *
' column in a worksheet and prints its address and the address *
' of the UsedRange to the Immediate Window. *
'*******************************************************************************
Sub LastUR_Column_UsedRange()
Const cVntCol As Variant = "A" ' Column
Dim objRngT As Range ' Target Range
With ThisWorkbook.Worksheets("Sheet1")
If .Cells(.UsedRange.Rows.Count + .UsedRange.Row - 1, cVntCol).Row = 1 _
And .Cells(1, Columns.Count).End(xlToLeft).Column = 1 _
And IsEmpty(.Cells(1, 1)) Then
Debug.Print "objRngT = Nothing (Empty Worksheet)"
Else
Set objRngT = .Cells(.UsedRange.Rows.Count + .UsedRange.Row - 1, cVntCol)
Debug.Print "objRngT = " & objRngT.Address & " calculated from the " _
& "used range (" & .UsedRange.Address & ")."
Set objRngT = Nothing
End If
End With
End Sub
'*******************************************************************************
'*******************************************************************************
' Purpose: Using the UsedRange Property, creates a reference to the cell *
' range at the intersection of the last used row and a specified *
' column in a worksheet and prints subresults and its address *
' to the Immediate Window. *
'*******************************************************************************
Sub LastUR_Column_UsedRange_Lesson()
' When you declare the column as variant you can use
' column letter or number e.g. "A" or 1, "D" or 4 ...
Const cVntCol As Variant = "A" ' Column
Dim objRngT As Range ' Target Range
Dim lngLast As Long ' Last Row
Dim lngRows As Long ' Number of Rows
Dim lngFirst As Long ' First Row
With ThisWorkbook.Worksheets("Sheet1")
' Finding first row and number of rows is easy.
lngFirst = .UsedRange.Row
Debug.Print "lngFirst = " & lngFirst
lngRows = .UsedRange.Rows.Count
Debug.Print "lngRows = " & lngRows
' Note1: Only when there is data in the first row, the number of rows
' is equal to the last row.
' Therefore we have to calculate the last row.
lngLast = lngRows + lngFirst - 1
Debug.Print "lngLast = " & lngLast
' Now imagine you have the first data in row 2, and you have 3 rows
' which would mean the last data is in row 4 (rows 2, 3, 4). So when you add
' 2 + 3 = 5, you have to subtract 1 row, because you counted row 2 twice.
' Note2: If there is data in the first row then lngFirst = 1.
' So the formula will calculate:
' lnglast = lngRows + 1 - 1
' lngLast = lngRows + 0
' which proves the statement in Note1.
' The previous three lines could have been written in one line:
lngLast = .UsedRange.Rows.Count + .UsedRange.Row - 1
Debug.Print "lngLast = " & lngLast & " (One Row Version)"
' Now we have all the ingredients for the Target Range.
Set objRngT = .Cells(lngLast, cVntCol)
Debug.Print "objRngT = " & objRngT.Address _
& " (Before Check if Empty)"
' And again all this could have been written in one line:
Set objRngT = .Cells(.UsedRange.Rows.Count + .UsedRange.Row - 1, cVntCol)
Debug.Print "objRngT = " & objRngT.Address & " (One Row Version)" _
& " (Before Check if Empty)"
' then you wouldn't need variables lngLast, lngFirst and lngRows. On the
' other hand you wouldn't have learned how this big formula was created.
' Now the problem is that if the worksheet is empty, UsedRange will show
' the cell in the first row as the used range. So we have to address this
' issue by checking if all of the following three conditions are true.
' - Check if the resulting cell range is in the first row (1).
' - Check if from the end of the first row to the beginning the result
' is the first cell (1) (all other cells are empty).
' - Check if the cell ("A1") is empty.
If objRngT.Row = 1 And _
.Cells(1, Columns.Count).End(xlToLeft).Column = 1 And _
IsEmpty(.Cells(1, 1)) Then
Debug.Print "objRngT = Nothing (Empty Worksheet)"
Else
Debug.Print "objRngT = " & objRngT.Address
End If
' Although this is a working code, we can conclude that we should have done
' this checking at the beginning which will be done in the advanced version.
End With
Set objRngT = Nothing
End Sub
'*******************************************************************************
答案 3 :(得分:0)
我将其称为最安全且最优雅的方式:使用 Find 方法。
'*******************************************************************************
' Purpose: Using the Find method, creates a reference to the cell range at *
' the intersection of the last used row and a specified column *
' in a worksheet and prints its address to the Immediate window. *
'*******************************************************************************
Sub LastUR_Column_Find()
Const cVntCol As Variant = "A" ' Column Letter or Number ("A" or 1)
Dim objRngT As Range ' Target Range
With ThisWorkbook.Worksheets("Sheet1")
If Not .Cells.Find("*", .Cells(.Rows.Count, .Columns.Count), -4123, , 1) _
Is Nothing Then
Set objRngT = .Cells(.Cells.Find("*", , , , , 2).Row, cVntCol)
Debug.Print "objRngT = " & objRngT.Address
Set objRngT = Nothing
Else
Debug.Print "objRngT = Nothing (Empty Worksheet)"
End If
End With
End Sub
'*******************************************************************************
' Remarks: If you carefully study the "Find method as it applies to *
' the Range object." from "Visual Basic Help", you will realize *
' why exactly those four arguments and their parameters in *
' the If statement must be included and why three of them can *
' be omitted, but a new one has to be added in the Else clause. *
'*******************************************************************************