Страницы: 1
RSS
В чём отличие циклов «For Each …» для ячеек диапазона и элементов массива, Different «For Each …» cycles for Cells in Range vs Elements of Array
 
Приветствую!
Закрепляю в теме, чтобы самому не забыть, а также отправлять сюда и не писать тесты каждый раз

Используя оператор For…Each…Next, можно ошибиться в понимании порядка обработки ячеек диапазона и элементов 2-х мерного массива
Скрины, файл и коды

Цикл For Each Cell In Range идёт сначала по СТРОКАМ, потом по СТОЛБЦАМ
Правильнее будет сказать, что коллекция ячеек диапазона формируется таким образом, что цикл For Each по ней будет равносилен коду ниже
Визуализация через двойной цикл

Цикл For Each Element In Array2D идёт сначала по "СТОЛБЦАМ", потом по "СТРОКАМ"
Правильнее будет сказать, что коллекция элементов массива формируется таким образом, что цикл For Each по ней будет равносилен коду ниже
Визуализация через двойной цикл
Изменено: Jack Famous - 17.02.2022 15:59:36
Во всех делах очень полезно периодически ставить знак вопроса к тому, что вы с давних пор считали не требующим доказательств (Бертран Рассел) ►Благодарности сюда◄
 
Цитата
Jack Famous написал:
Цикл For Each Cell In Range идёт сначала по СТРОКАМ, потом по СТОЛБЦАМ
Цикл For Each Element In Array2D идёт сначала по СТОЛБЦАМ, потом по СТРОКАМ
Добрый день, Алексей.
Хорошо, что модераторы подчистили тему, т.к. с утра здесь что-то эмоционально обсуждали и по ходу поменяли термин "перебор по" на "ИДЕТ".
Термин "ИДЕТ" может толковаться по разному, например: пошел я по строкам 1-го столбца, потом по строкам 2-го.
Или, наоборот: потопал по всем столбцам первой строки, потом 2-й и т.д. Об этом же с утра здесь вроде спорили.

По-моему, в начале темы всегда полезно конкретно обозначить свою проблему, например: "Используя оператор For-Each-Next, можно ошибиться в понимании порядка обработки ячеек диапазона и элементов 2-х мерного массива".
А то вдруг это на самом деле окажется не проблема – мы же не знаем того, чего не знаем.
При приведенном мною описании проблемы, причина (понимание устройства коллекции ячеек диапазона) не спутается со следствием – интерпретацией кем-то работы оператора For-Each-Next, который, вообще-то, всегда работает однозначно.

Диапазон ячеек, это коллекция объектов ячеек.
Оператор For-Each-Next с любыми коллекциями работает в порядке следования индекса элемента коллекции от меньшего к большему.
У каждой ячейки диапазона (читай – коллекции объектов) Range тоже есть свой индекс. К ячейке можно обращаться по такому индексу, например Range("A1:B2").Item(2) это ячейка B1, а не A2, как некоторые могут неправильно подумать. И оператор For-Each-Next здесь совершенно не причем, он тупо перебирает коллекцию, которую ему подсунули: ячейки диапазона (читай – элементы коллекции) в порядке возрастания индекса ячеек.

Теперь пояснения по устройству массивов.
Строго говоря, у массива нет ни строк, ни столбцов, у него – размерности, каждая из которых может начинаться не обязательно с единичного индекса.
Например: Dim a(0 To 3, 10 To 11)
Физически же в памяти как элементы коллекции, так и элементы массивы всегда располагаются в непрерывном диапазоне адресов, как одномерный массив.
Но, чтобы немного «очеловечить» их восприятие и позволить произвольный перебор, у массива есть структура, которая позволяет (логически) обращаться к элементам по логическим индексам элемента, при этом внутри индекс всегда пересчитывается в индекс одномерного, так как в памяти все элементы лежат в непрерывном диапазоне адресов.

Для 2-мерного массива представление об 1-й разрядности как о строках – это вольная интерпретация конкретного программиста, у другого это легко может ассоциироваться со столбцами или ещё с каким-либо попугаями. Это лучше конкретизировать.

С массивами оператор For-Each-Next работает по порядку физического (одномерного) хранения элементов массива. С точки зрения разрядностей массива это равносильно перебору от элемента с наименьшим индексом - a(0, 11) к наибольшему a(3, 11) для примера выше, перебирая поочередно элементы 1-й разрядностей ...-a(1,11)-a(2,11)-…, потом инкрементировать индекс 2-й разрядности, если она есть, и.т.д.

Если хочется упростить понимание обработки For-Each-Next, ассоциируя 2-мерный массив с диапазоном ячеек Excel, то порядок обработки такой:
1. Ячейки диапазона: Слева-Направо-Вниз
2. Элементы 2-мерного массива: Сверху-Вниз-Направо

Но, еще раз подчеркну, оператор For-Each-Next здесь не причем.

Пример кода для понимания устройства коллекции Range:
Код
Sub Test1()
  ' For-Each-Next
  Dim rng As Range, cell As Range
  Set rng = Range("A1:B2")
  Debug.Print "Cell"
  For Each cell In rng.Cells
    Debug.Print cell.Address(0, 0)
  Next
End Sub

Sub Test2()
  ' Аналог For-Each-Next
  Dim i As Long, rng As Range
  Set rng = Range("A1:B2")
  Debug.Print "Item"
  For i = 1 To rng.Cells.Count
    Debug.Print rng.Item(i).Address(0, 0)
  Next
End Sub

P.S. Извиняюсь за много слов
Изменено: ZVI - 17.02.2022 15:31:37
 
ZVI, рад вас видеть!  8)
Цитата
ZVI: оператор For-Each-Next здесь совершенно не при чём … с любыми коллекциями работает в порядке следования индекса элемента коллекции от меньшего к большему
это, конечно, важное замечание, но, боюсь, что более "корректное" название темы типа "Коллекция ячеек диапазона и элементов двумерного массива, полученного из этого диапазона имеют разные индексы" не оставит шансов ищущим, а также отобъёт всякое желание открывать тему даже у тех, кто её видит  :D

Цитата
ZVI: поменяли термин "перебор по" на "ИДЕТ" … может толковаться по-разному
для этого я и показал кодом из 2ух циклов, что имею ввиду
Дополнил строками с более корректным определением и добавил кавычки к "строкам" и "столбцам" массива

Подытожу с учётом новой и полной информации:
Цикл For Next просто перебирает все элементы коллекции "по порядку", то есть по индексам от первого […индекса, который может быть и 0] до последнего
Коллекции ячеек диапазона и элементов массива формируются по-разному, поэтому и индексы при переборе будут разные (если только это не перебор одной строки диапазона/столбца диапазона/размерности массива)

Всё, что я хотел сказать этой темой — rng(n)<>arr(n) при arr=rng.Value и rng.Areas=1

ZVI, ещё раз спасибо за полный разбор — про коллекции я не "докопал", конечно и только "по верхам" прошёл  :)  :idea:

Цитата
ZVI: P.S. Извиняюсь за много слов
думаю, что выражу общее мнение всех местных: наоборот, хотелось бы читать вас гораздо чаще  ;)
Изменено: Jack Famous - 17.02.2022 14:46:07
Во всех делах очень полезно периодически ставить знак вопроса к тому, что вы с давних пор считали не требующим доказательств (Бертран Рассел) ►Благодарности сюда◄
 
Цитата
Jack Famous написал:
боюсь, что более "корректное" название темы типа "Коллекция ячеек диапазона и элементов двумерного массива, полученного из этого диапазона имеют разные индексы" не оставит шансов ищущим, а также отобъёт всякое желание открывать тему даже у тех, кто её видит  
Алексей, про краткое название темы я ничего не предлагал.
По названию проблема мне не ясна, так как реально нет отличий работы цикла «For Each …» для ячеек диапазона и элементов массива - и те и другие обрабатываются в порядке индексов элементов.
Для массива это неявный одномерный индекс, для ячеек - явный.
Мое предложение было - чтобы не было необходимости читать цепочку кодов и о чем-то самому догадываться, описывать проблему кратко в начале темы словами, в моем тексте выше это было сформулирована так:
"Используя оператор For-Each-Next, можно ошибиться в понимании порядка обработки ячеек диапазона и элементов 2-х мерного массива".
Так как понимание работы оператора и его реальная работа - это не всегда одно и тоже.
Изменено: ZVI - 17.02.2022 15:13:21
 
Цитата
ZVI: "Используя оператор For-Each-Next, можно ошибиться в понимании порядка обработки ячеек диапазона и элементов 2-х мерного массива".
если модераторы посчитают нужным, то я совсем не против  :)
Но вообще, считаю его более "тяжёлым" для поиска (особенно дублирование на английском, что я стараюсь в последнее время делать  :D ), хоть и, безусловно, более корректным
Во всех делах очень полезно периодически ставить знак вопроса к тому, что вы с давних пор считали не требующим доказательств (Бертран Рассел) ►Благодарности сюда◄
 
Цитата
ZVI написал:
2. Элементы 2-мерного массива: Сверху-Вниз-Направо
Владимир, приветствую. Осталось только вспомнить что массив не ограничен двумя измерениями :-) и появится вглубь и .... даже не знаю что делать с 4м :-)
Цитата
ZVI написал:
Range("B1:B2").Item(2) это ячейка B1
а вот тут готов поспорить.
По вопросам из тем форума, личку не читаю.
 
Цитата
Jack Famous написал: ...если модераторы посчитают нужным,
Алексей ну, прочитайте, пожалуйста, что я написал.
Мое предложение касалось не названия темы, а описания проблемы в начале текста сообщения #1

Цитата
БМВ написал: Владимир, приветствую.
Добрый день, Михаил.
1. Там конкретизировано, что это касается только 2-мерного массива, ассоциированного с диапазоном ячеек,
2. Опечатка, спасибо! Исправил на A1:B2
 
Цитата
БМВ: Осталось только вспомнить что массив не ограничен двумя измерениями :-) и появится вглубь и .... даже не знаю что делать с 4м :-)
а мне наоборот стало ясно после ликбеза от Владимира, что будет

UPD : добавил в шапку темы код и файл с тестом 4ёхмерного массива

Цитата
ZVI: Мое предложение качалось не названия темы, а формулировки описания проблемы в начале текста сообщения #1
готово  :)
Изменено: Jack Famous - 17.02.2022 16:00:25
Во всех делах очень полезно периодически ставить знак вопроса к тому, что вы с давних пор считали не требующим доказательств (Бертран Рассел) ►Благодарности сюда◄
 
Всех приветствую! Владимир, как всегда познавательно. Добавлю от себя немного. Да все массивы, это единый непрерывный блок в памяти. Можно сказать одномерный массив. Размерности это условность. Алексей, помнишь мою функцию по очень быстрому смены размерностей (она как раз и использует это свойство).  Вся проблема (и у меня она тоже возникает постоянно) в том, что массив ячеек в Excel ( и в Excel C API) хранится как слева-направо-вниз. В таком же порядке идет пересчет ячеек. Так решили напилить.
А вот массивы СОМ (в т.ч. и в VBA) это порядок сверху-вниз-направо.
ДВА РАЗНЫХ подхода в хранении элементов массива!  Отчего так, наверное исторически, надо гуглить.
Я даже делал конвертацию элементов между массивами СОМ (VBA) и C API EXCEL
Поэтому кажется, что For…Each…Next работает по разному. Но нет он просто перебирает ПО ПОРЯДКУ хранимые в памяти элементы массива.
Изменено: bedvit - 17.02.2022 15:53:40
«Бритва Оккама» или «Принцип Калашникова»?
 
Цитата
Jack Famous написал:
готово
Спасибо! Осталось еще раз попросить модератора почистить тему, оставив только #1, т.к. остальное теперь - лирика  :D
 
Цитата
bedvit написал: А вот массивы СОМ (в т.ч. и в VBA) это порядок сверху-вниз-направо.
Добрый день, Виталий! Все верно, в инете куча примеров C/C++ для обоих вариантов.
 
Цитата
bedvit: помнишь мою функцию по очень быстрому смены размерностей
такое не забыть - мгновенное переопределение  :idea:

Цитата
ZVI: Осталось еще раз попросить модератора почистить тему, оставив только #1, т.к. остальное теперь - лирика
ДАЩАС
Я категорически против  :)

Добавил тест 4ёх мерного массива (спойлер: я всё правильно понял  :) )
Изменено: Jack Famous - 17.02.2022 16:04:46
Во всех делах очень полезно периодически ставить знак вопроса к тому, что вы с давних пор считали не требующим доказательств (Бертран Рассел) ►Благодарности сюда◄
 
Ну тогда , наверно зацепим что  CELLS(2) = ITEM(2) .  и  то что Areas сравнима с третьим измерением массива.

Ну а касаемо самой темы, которая видимо была навеяна  Алексею этой достаточно было написать что нужно транспонировать.
По вопросам из тем форума, личку не читаю.
 
Цитата
БМВ: была навеяна  Алексею  этой
даже именно твоим сообщением, кстати  :D
Во всех делах очень полезно периодически ставить знак вопроса к тому, что вы с давних пор считали не требующим доказательств (Бертран Рассел) ►Благодарности сюда◄
 
Цитата
Jack Famous написал:
кстати  
что кстати.... развели тут понимаешь  "душевную компанию 2", междусобойчик :-)

Цитата
ZVI написал:
Если хочется упростить понимание обработки For-Each-Next, ассоциируя 2-мерный массив с диапазоном ячеек Excel, то порядок обработки такой:1. Ячейки диапазона: Слева-Направо-Вниз2. Элементы 2-мерного массива: Сверху-Вниз-Направо
думаю проще описать это тем что при For-Each-Next в диапазоне меняется сперва второй индекс, потом первый, а в массиве наоборот.
На самом деле интересно, почем у такую концепцию заложили разработчики, ну разе что читать привыкли в той же последовательности что и ячейки на листе.
Изменено: БМВ - 17.02.2022 18:54:49
По вопросам из тем форума, личку не читаю.
Страницы: 1
Наверх