WorksheetFunction.Match как массив с переменным диапазоном - PullRequest
0 голосов
/ 23 ноября 2018

Я пытаюсь реализовать функцию .Match в виде массива с переменным диапазоном в VBA, чтобы найти первую ненулевую ячейку в определенном диапазоне.

Однако в настоящее время я получаю только ошибку времени выполнения 1004.

Любая помощь очень ценится!Спасибо

Set myRange = Worksheets("Portf_Mod").Range("AB368:CY368") 
With Application.WorksheetFunction
    Date_col = .Match(True, [myRange <> 0], 0)
End With

Ответы [ 4 ]

0 голосов
/ 23 ноября 2018

Впервые я столкнулся с "формулой массива" в VBA.Это не так, но не очень очевидно для понимания / устранения неполадок.На моей машине [где диапазон имел все пустые ячейки, он выдает ошибку [myRange <> 0] = Error 2092, затем в функции Match, затем получает другую ошибку ...

Формулы массива хороши только на листе формул,но я чувствую, что вы должны избегать их в VBA.У вас есть возможность использовать петли в VBA, поэтому не стесняйтесь их использовать!Хотя ваш черед, хотя и явный, насколько это возможно, является ключевым при написании программного обеспечения (так что вы поймете это позже!).

Мое предложение будет следующим:

Option Explicit

Function FindDateColumnInRange(ByVal RangeToLookIn As Range) As Long

If RangeToLookIn.Rows.Count <> 1 Then
    'The range you're looking in has more than one row
    'what should you do in this case? Look only in the first row?

Else

    Dim i As Long
    'The range has only one row
    For i = 0 To RangeToLookIn.Columns.Count - 1
        If RangeToLookIn.Item(1, i).Value <> 0 Then
            'should you verifiy that the value is a date value?
            FindDateColumnInRange = RangeToLookIn.Item(1, i).Column
            Exit Function
        End If
    Next
End If

'the range didn't have a value different from 0
FindDateColumnInRange = 0

End Function

В действии вы быget:

Sub Test()

Dim MyRange As Range
Set MyRange = Worksheets("Portf_Mod").Range("AB368:CY368")
Dim date_col As Integer

date_col = FindDateColumnInRange(MyRange)

If date_col = 0 Then
    'There was no date in your range
End If

End Sub

Да, это намного длиннее, чем предложения SJR, но охватывает все исключения, и вы можете контролировать, как будет выглядеть, если вы будете передавать многомерный массив (сначала проходите по строкам, а затем по столбцам)или наоборот).

0 голосов
/ 23 ноября 2018

Поскольку вы используете VBA , вместо использования Match вы можете использовать API для создания более явного и удобного кода:

Function FirstNonZeroCell(rng As Range) As Range
    Dim cell As Range
    For Each cell In rng.Cells
        If cell.Value <> 0 Then
            Set FirstNonZeroCell = cell
            Exit Function
        End If
    Next
End Function

Или, если вы хотитеболее компактная версия (но, на мой взгляд, менее читаемая):

Function FirstNonZeroCell(rng As Range) As Range
    For Each FirstNonZeroCell In rng.Cells
        If FirstNonZeroCell.Value <> 0 Then Exit Function
    Next
    Set FirstNonZeroCell = Nothing
End Function

Вот пример использования:

Sub test()
    Dim res As Range
    Set res = FirstNonZeroCell(Range("A1:Z100"))
    If Not res Is Nothing Then
        MsgBox "Found value " & res.Value & " in cell " & res.Address & "."
    Else
        MsgBox "No match has been found!"
    End If
End Sub
0 голосов
/ 23 ноября 2018

Я бы не использовал функцию Match для этого ...

Set myRange = Worksheets("Portf_Mod").Range("AB368:CY368") 
On Error Resume Next
Date_col = myRange.Find("*", LookIn:=xlValues, SearchOrder:=xlByColumns).Column
On Error GoTo 0
0 голосов
/ 23 ноября 2018

Думайте, что элемент массива отбрасывает ваш подход, поэтому здесь есть альтернатива.

Не ясно, хотите ли вы первое ненулевое значение или его позицию, так что это покрывает оба.

Date_col = Evaluate("MATCH(TRUE," & myRange.Address & "<>0,0)") 'returns position
Date_col = Evaluate("INDEX(" & myRange.Address & ",MATCH(TRUE," & myRange.Address & "<>0,0))") 'returns value
...