Оцените максимальную длину среди строк переменной длины в одномерном массиве с помощью Excel VBA

У меня есть одномерный массив, содержащий строки переменной длины. Я хочу найти максимальную длину среди этих строк, используя комбинацию функций EVALUATE, MAX и LEN.

Я знаю, что для рабочего листа Range, объявленного Rng, работает следующий код:

MX_LEN = EVALUATE("MAX(LEN(" & Rng.Address & "))")

Но я не могу добиться чего-то подобного с одномерным массивом Arr.

MX_LEN = EVALUATE("MAX(LEN(" & Arr & "))")

ИЗМЕНИТЬ:

Я получаю Runtime error 13: Type Mismatch с кодом ниже. Это двумерный массив, из которого я обращаюсь только к 1-му измерению.

Наблюдения:

  • Строки здесь немного длинные, примерно 100-200 символов каждая.

  • Я вижу, почему-то в Join отсутствуют начальные и конечные двойные кавычки.

Код:

MX = Application.Evaluate("MAX(LEN({""" & Join(Application.Transpose(Application.Index(Arr, 0, 1)), """, """) & """}))")

PS: я не хочу зацикливать массив, так как массив очень маленький.


person sifar    schedule 20.11.2019    source источник
comment
Конечно, если массив очень мал, зацикливание будет чрезвычайно быстрым.   -  person Rory    schedule 20.11.2019
comment
Вы имеете в виду, что массив очень большой?   -  person SJR    schedule 20.11.2019
comment
Проверьте мой ответ. Общая длина оцениваемой строки не может превышать 255 символов. Возможно, это делает не так, как вы хотите подойти к этой проблеме =)   -  person JvdV    schedule 20.11.2019


Ответы (1)


Хороший вопрос. Вам нужно Join массив в строку:

Sub Filtering()

Dim arr As Variant: arr = Array("Hello", "World", "Wide", "Web")

With Application
    Dim MX_LEN As Long: MX_LEN = .Evaluate("MAX(LEN({""" & Join(arr, """,""") & """}))")
End With

End Sub

Немного подробнее о том, почему это работает:

.Evaluate необходимо передать строку в виде действительной формулы. Поэтому нам нужно подумать, как мы запишем это на листе Excel. ОП упомянул, что MX_LEN = EVALUATE("MAX(LEN(" & Rng.Address & "))") сработало. Очень логично, потому что на листе, который будет читаться (давайте предположим, что rng ​​будет A1:A5):

=MAX(LEN(A1:A5))

Теперь, поскольку Evaluate распознает, что мы хотели ввести это как формулу массива, он вернет правильное значение.

ОП сказал, что хочет передать функцию массива. Поэтому мы можем обратить логику и подумать, как будет выглядеть функция на листе:

=MAX(LEN({"Hello", "World", "Wide", "Web"}))

Теперь нам просто нужно построить эту строку, используя Join, и не забыть фигурные скобки. Чтобы проверить, правильно ли мы его строим, можно проверить с помощью Debug.Print "MAX(LEN({""" & Join(arr, """,""") & """}))"


Если мы хотим имитировать это, но вместо этого для первого измерения двумерного массива мы можем применить следующее:

With Application
    MX_LEN = .Evaluate("MAX(LEN({""" & Join(.Transpose(.Index(arr, 0, 1)), """,""") & """}))")
End With

Одно замечание, как и во многих других случаях, длина строки не может превышать 255 символов. В противном случае Evaluate вернет ошибку (согласно документации)

Это означает, что .Evaluate нельзя использовать для больших строк, что делает цикл по массиву наиболее эффективной стратегией перехода.

Однако, если вы действительно не хотите зацикливаться, вы можете вместо этого заполнить ячейку формулой и прочитать результат ячейки value2:

With Application
    Sheet1.Range("A1").Formula = "=MAX(LEN({""" & Join(.Transpose(.Index(arr, 0, 1)), """,""") & """}))"
End With

Теперь вы можете прочитать это через:

MX_LEN = Sheet1.Range("A1").Value2
person JvdV    schedule 20.11.2019
comment
Интересно, почему это работает. Разве Join не создает строку? - person SJR; 20.11.2019
comment
@SJR Я как раз собирался спросить об этом :) - person Zac; 20.11.2019
comment
Это действительно так @SJR, но именно поэтому я включил скобки в полную строку для оценки. Проверьте также Debug.Print "MAX(LEN({""" & Join(arr, """,""") & """}))". - person JvdV; 20.11.2019
comment
@ Зак, это может сбивать с толку, но для оценки Evaluate нужно передать строку. Поэтому это работает. Примечание: MX_LEN = EVALUATE("MAX(LEN(" & Rng.Address & "))") работало для OP, потому что rng.Address возвращало строку для объединения в Evaluate. - person JvdV; 20.11.2019
comment
Ах да, на самом деле я пропустил двойные кавычки вокруг запятых, что предположительно превращает его в 4 строки. И фигурные скобки говорят ему оценивать каждый отдельно? - person SJR; 20.11.2019
comment
Это может быть мой недостаток знаний, но кажется очень умным способом делать вещи! - person Zac; 20.11.2019
comment
@SJR, если вы найдете этот материал интересным, вас также может заинтересовать это и это. Собственно, вы там и ответили :) - person JvdV; 20.11.2019
comment
@Zac, если вы найдете этот материал интересным, вас также может заинтересовать это и это - person JvdV; 20.11.2019
comment
Очень интересное чтение. Мне особенно нравится использование CHOOSE - person Zac; 20.11.2019
comment
@sifar, с моей стороны проблем нет. Я пробовал. Можете ли вы включить примеры данных в свой вопрос? И результат Debug.Print "MAX(LEN({""" & Join(Application.Transpose(Application.Index(Arr, 0, 1)), """, """) & """}))" - person JvdV; 20.11.2019
comment
@JvdV, ты прав. я думаю, что да, потому что часть текста составляет 255 символов. Думаю, нет другого способа, кроме как использовать цикл, верно? - person sifar; 20.11.2019
comment
@Sifar Сифар, ну .... ты заранее знаешь количество элементов, которые будут в твоем массиве? - person JvdV; 20.11.2019
comment
это будет максимум от 5 до 20 предметов. не больше. - person sifar; 20.11.2019
comment
Без фиксированного размера, я думаю, вам придется использовать петлю. Иначе был бы другой путь. Теперь зацикливание - ваш лучший выбор (который, как упоминал @Rory, в любом случае должен быть очень быстрым) - person JvdV; 20.11.2019
comment
Я проверил, максимальный размер был 242. Это сделает функцию Evaluate неработоспособной? В любом случае, теперь я альтернативно использовал Loop. - person sifar; 20.11.2019
comment
@Sifar Сифар, это действительно было бы виновником. Вся строка: =MAX(LEN({"Hello", "World", "Wide", "Web"})) не должна превышать 255 символов. Я все еще пытаюсь найти другой способ, но я думаю, что петля - ваш лучший выбор =) - person JvdV; 20.11.2019
comment
Спасибо @JvdV, ваш совет ценен для меня. - person sifar; 20.11.2019
comment
@Sifar Сифар, есть еще один способ, который я бы не рекомендовал, но я обновлю ответ. - person JvdV; 20.11.2019