Страницы: 1
RSS
VBA: Почему ошибка Run-time error '13': Type mismatch, если в массиве один элемент текст
 
Добрый день,

При получении в массив единственного элемента, вход в цикл For each возвращает ошибку Run-time error '13': Type mismatch
Если в массиве два и более элементов, цикл отрабатывает
Код
    Dim ВыкладкаФайлы As Variant
           
Sheets("Генератор").Select
          
lLastRow = Sheets("Генератор").Cells(Rows.Count, 19).End(xlUp).Row
Sheets("Генератор").Range(Cells(1, 19), Cells(lLastRow, 19)).Select
ВыкладкаФайлы = Selection.Value2

For Each Filename In ВыкладкаФайлы ' здесь Run-time error '13': Type mismatch
Debug.Print Filename
 
For Each работает с коллекцией или массивом
Dim ВыкладкаФайлы As Variant - и где здесь видно, что это? Да, какая-то переменная, подходит и для значения, и для массива...

Выделили (выделять не обязательно) одну ячейку, получили: ВыкладкаФайлы - обычная переменная , в которой хранится значение.
 
Здравствуйте, vikttur,

Dim ВыкладкаФайлы() As Variant ? (если я правильно понял)
 
Для массива - да.
Но получите ошибку при заполнении массива одним значением :)
 
Но как же этого можно избежать? ))
 
Не входить в цикл, если один элемент.
Можно в массив взять два столбца, но обрабатывать только первый (For i = 1 To UBound(массив)). Медленнее и лишнюю память откусит.
 
Дело в том, что у меня там несколько последовательно вложенных друг в друга циклов
(разбивка списка по критерию / разбивка категории на примерно равные части / формирование содержимого нового файла / ...)
и когда категория состоит из единственной части, мне не очень понятно как корректно прописать обход цикла – буду благодарен за помощь

т.е. от количества уровней вложенности голова уже прилично кружится)
 
Цитата
Дмитрий Марков написал: прописать обход цикла
Код
If  lLastRow >1 Then
    цикл
Else
    не цикл
End If

Цитата
от количества уровней вложенности голова уже прилично кружится
Это головокружение от счастья ("все мои!!!") :)
Если вложенных циклов много - поора думать об оптимизации.
 
Цитата
Дмитрий Марков написал:
как корректно прописать обход цикла
вариант
Код
if lLastRow=1 Then
без цикла
ELSE
цикл
end if 
Изменено: V - 22.01.2021 12:27:34
 
Цитата
vikttur написал:
Если вложенных циклов много - пора думать об оптимизации.
Но ведь это уже совсем другой уровень! Холмс!
 
V, большое спасибо!
 
Ну вообще все делается иначе обычно.
Код
Dim ВыкладкаФайлы
ВыкладкаФайлы = Selection.Value2
If Not IsArray(ВыкладкаФайлы) Then
    ReDim ВыкладкаФайлы(1 to 1, 1 to 1)
    ВыкладкаФайлы(1,1) = Selection.Value2
end if
а далее работаем с массивом и все.
Даже самый простой вопрос можно превратить в огромную проблему. Достаточно не уметь формулировать вопросы...
 
Цитата
vikttur написал:
Но получите ошибку при заполнении массива одним значением
Не пудри мозги!  :)
При заполнении массива 1 значением ошибки не будет.
А при заполнении с листа, при условии, что в диапазоне 1 ячейка, массива не будет.
 
Дмитрий(The_Prist) Щербаков, большое спасибо!

Цитата
RAN написал: А при заполнении с листа, при условии, что в диапазоне 1 ячейка, массива не будет
RAN, в том-то и дело, что заполнение происходит с листа, а массив () – всепогодный, если верно понимаю
 
Дмитрий(The_Prist) Щербаков, приветствую, Дим!
Добавлю, что можно подсократить и ускорить для циклов:
Во всех делах очень полезно периодически ставить знак вопроса к тому, что вы с давних пор считали не требующим доказательств (Бертран Рассел) ►Благодарности сюда◄
 
Цитата
RAN написал: Не пудри мозги!
Котелком прикрылся. Тебе запудришь...  :)
За уточнение спасибо. Я написал только применительно к конкретному случаю.

Цитата
RAN написал: А при заполнении с листа, при условии, что в диапазоне 1 ячейка, массива не будет.
Массив объявленный останется. Ошибка будет :)
Код
Sub Test_()
    Dim a()
    
    a = Range("A1").Value
End Sub
 
Цитата
Jack Famous написал:
можно подсократить и ускорить для циклов
ускорения тут не вижу, если честно...Сокращение строк - да. Но я этим не страдаю :)
И там и там инициализация массива займет одинаковое кол-во времени(у меня через ReDim, у тебя через Dim). Только в моем коде этой инициализации не будет, если выделено более одной ячейки. Да, есть однозначное присвоение значения переменной, но оно есть и у тебя.
Плюс, в твоем коде идет сначала получение значений из ячеек, а потом перекидывание этих значений из одного массива в другой(одного значения). Не уверен, что такой подход что-то ускорит.
Даже самый простой вопрос можно превратить в огромную проблему. Достаточно не уметь формулировать вопросы...
 
Нужно мяукнуть, и будет вам массив из одной ячейки.
Код
Sub мяу()
    Dim ar
    ar = Selection.Value
    If Not IsArray(ar) Then
        ReDim ar(1 To 1, 1 To 1)
        ar(1, 1) = Selection.Value
    End If
End Sub


PS Когда писал, сообщения 12 не видел.  :)
Изменено: RAN - 22.01.2021 14:36:09
 
Цитата
Дмитрий(The_Prist) Щербаков: ускорения тут не вижу, если честно
А так?
инициация у меня 1 раз, а у тебя будет [переопределение] (для этого примера) — для каждой области, состоящей из одной ячейки ;)
Изменено: Jack Famous - 22.01.2021 15:28:19 (Добавил указание про переопределение)
Во всех делах очень полезно периодически ставить знак вопроса к тому, что вы с давних пор считали не требующим доказательств (Бертран Рассел) ►Благодарности сюда◄
 
Цитата
Jack Famous написал:
у тебя будет (для этого примера) — для каждой области
не, ну если таким путем идти, то конечно. Только ты забываешь и еще одну вещь: переопределение через ReDim не одно и тоже, что инициализация :) И происходит быстрее, т.к. сам массив по сути уже есть.
Если бы мне было не лень - может сделал бы сравнительный анализ. Но что-то подсказывает, что выигрыша в скорости в твоем варианте ожидать особо не стоит. Потому что переопределение массива явно быстрее, чем пихание сначала в заранее определенный массив одной ячейки, а потом пихание его в другой массив, который на лету должен будет все равно переопределиться(внутренними ресурсами). Т.е. по сути тот же ReDim все равно будет вызван...Могу ошибаться, конечно, но что-то такое в памяти всплывает из области назначения значений массиву на лету.
Даже самый простой вопрос можно превратить в огромную проблему. Достаточно не уметь формулировать вопросы...
 
Цитата
Дмитрий(The_Prist) Щербаков: переопределение массива явно быстрее, чем пихание
ща проверю и отпишусь в этот пост  :)
250 против 270 мс. Мои 2 строчки быстрее — незначительно, но стабильно
не знаю, как там технически, но переопределять что-то мне кажется более долгим, чем присваивать в готовое
Изменено: Jack Famous - 22.01.2021 15:37:28
Во всех делах очень полезно периодически ставить знак вопроса к тому, что вы с давних пор считали не требующим доказательств (Бертран Рассел) ►Благодарности сюда◄
 
Цитата
Jack Famous написал:
переопределять что-то мне кажется более долгим, чем присваивать в готовое
тут как бы...Да, в данном конкретном случае, скорее всего так и есть. Ибо значений мало. Но если речь не про одну ячейку - то все же нет.
А в данном конкретном случае таки да - твой вариант выигрывает по скорости. Но использовать я все равно буду свой  8)  
Даже самый простой вопрос можно превратить в огромную проблему. Достаточно не уметь формулировать вопросы...
 
Цитата
Дмитрий(The_Prist) Щербаков: значений мало. Но если речь не про одну ячейку - то все же нет
так в примере же цикл на  млн - как одно-то?)))
Цитата
Дмитрий(The_Prist) Щербаков: использовать я все равно буду свой
разница в рамках погрешности, так что вообще ничего не потеряешь  :)
Во всех делах очень полезно периодически ставить знак вопроса к тому, что вы с давних пор считали не требующим доказательств (Бертран Рассел) ►Благодарности сюда◄
 
Цитата
Jack Famous написал:
так в примере же цикл на  млн - как одно-то?)
о нет, я не про то. Я про то, что если в массив загонять не одну ячейку, а куда больше :)
Даже самый простой вопрос можно превратить в огромную проблему. Достаточно не уметь формулировать вопросы...
 
Цитата
Дмитрий(The_Prist) Щербаков написал: Ну вообще все делается иначе...  работаем с массивом и все
Дмитрий, в код очень удачно зашла Ваша конструкция, в основном потому, что на месте 'выворачивает') переменную в массив

Большое спасибо всем-всем, за направление, помощь, и конструктив) Всех благ!  
 
Дмитрий(The_Prist) Щербаков, а почему сразу не проверять диапазон\ячейку?

Код
Dim arr()
If IsArray(Selection.Value) Then
     arr = Selection.Value
Else
     ReDim arr(1 To 1, 1 To 1)
     arr(1, 1) = Selection.Value
End If

или, в стиле Jack Famous:

Код
Dim arr(), arrOne(1 To 1, 1 To 1)
If IsArray(Selection.Value) Then
     arr = Selection.Value
Else
     arrOne(1, 1) = Selection.Value
     arr = arrOne
End If
 
Цитата
dhead: почему сразу не проверять диапазон\ячейку?
и кода больше и по времени
Самый короткий вариант. если цикл For Each или нужен порядок "смотрим строки, а потом столбцы":
Код
Dim x, arr
arr=Selection.Value
If Not IsArray(arr) then arr=Array(arr)

For Each x in arr
' … Code
Next x
Медленнее (из-за работы функции Array() ), чем заранее объявить aOne(1 To 1, 1 To 1) и, если Selection будет состоять из ячейки, но настолько незначительно, что можно пренебречь.
Изменено: Jack Famous - 15.11.2023 10:44:52
Во всех делах очень полезно периодически ставить знак вопроса к тому, что вы с давних пор считали не требующим доказательств (Бертран Рассел) ►Благодарности сюда◄
Страницы: 1
Наверх