Vba excel объединение массивов
Массив — это набор значений, которые являются терминами элементы, логически взаимосвязаны друг с другом. Например, массив может состоять из числа учащихся в словаре грамматики. Каждый элемент массива — это количество учащихся одного уровня. Аналогичным образом массив может состоять из оценок учащегося для класса. Каждый элемент массива является однозначным.
Для хранения каждого элемента данных можно использовать отдельные переменные. Например, если наше приложение анализирует оценки учащихся, можно использовать отдельную переменную для каждой категории учащегося, например englishGrade1 , и englishGrade2 т. д. Этот подход имеет три основных ограничения:
- Во время разработки мы должны знать, сколько оценок нужно обменять.
- Обработка большого количества оценок быстро оказывается неудобной. Это, в свою очередь, значительно повышает вероятность возникновения серьезных ошибок в приложении.
- Его сложно поддерживать. Для каждого нового добавляемого класса необходимо, чтобы приложение было изменено, перекомпилировано и развернуто.
Используя массив, можно ссылаться на эти связанные значения по одному и тому же имени и использовать число, которое называется индексом или подиндексом для обозначения отдельного элемента в зависимости от его позиции в массиве. Индексы в диапазоне от 0 до 1 меньше, чем общее число элементов в массиве. при использовании синтаксиса Visual Basic для определения размера массива указывается его самый высокий индекс, а не общее число элементов в массиве. Можно работать с массивом как с единицей, а возможность итерации элементов освобождает вас от необходимости знать, сколько элементов оно содержит во время разработки.
Несколько простых примеров перед подробным описанием:
Элементы массива в простом массиве
Давайте создадим массив с именем students для хранения числа учащихся в каждом классе в школе. Индексы элементов находятся в диапазоне от 0 до 6. Использование этого массива проще, чем объявление семи переменных.
На следующем рисунке показан students массив. Для каждого элемента массива:
индекс элемента представляет школьный класс (индекс 0 представляет детский сад);
значение, содержащееся в элементе, представляет число учеников в этом классе.
в следующем примере содержится код Visual Basic, который создает и использует массив:
В этом примере выполняется три вещи:
- Он объявляет students массив с семью элементами. Число 6 в объявлении массива указывает последний индекс в массиве; он меньше, чем число элементов в массиве.
- Он присваивает значения каждому элементу в массиве. Доступ к элементам массива осуществляется с помощью имени массива, включая индекс отдельного элемента в круглых скобках.
- В нем перечисляются все значения массива. В примере используется For оператор для доступа к каждому элементу массива по номеру индекса.
students Массив в предыдущем примере является одномерным массивом, так как он использует один индекс. Массив, использующий более одного индекса или подстрочного, называется многомерным. Дополнительные сведения см. в остальной части этой статьи и в разделе измерения массива в Visual Basic.
Создание массива
Размер массива можно определить несколькими способами.
Размер можно указать при объявлении массива:
Можно использовать предложение, New чтобы указать размер массива при его создании:
При наличии существующего массива его размер можно переопределить с помощью ReDim инструкции. Можно указать, что ReDim инструкция сохранит значения в массиве, или можно указать, что он создает пустой массив. В приведенном ниже примере показаны различные варианты использования оператора ReDim для изменения размера существующего массива.
Дополнительные сведения см. в описании оператора ReDim.
Сохранение значений в массиве
К любой позиции в массиве можно получить доступ, используя индекс типа Integer . Вы можете сохранять и извлекать значения массива, ссылаясь на позицию в нем с помощью индекса, заключенного в скобки. Индексы для многомерных массивов разделяются запятыми (,). Для каждого измерения массива требуется один индекс.
В следующем примере показаны некоторые инструкции, которые хранят и извлекают значения в массивах.
Заполнение массива литералами массива
С помощью литерала массива можно заполнить массив начальным набором значений во время его создания. Литерал массива состоит из списка разделенных запятыми значений, заключенных в фигурные скобки ( <> ).
При создании массива с помощью литерала массива можно либо указать тип массива, либо использовать определение типа для задания типа массива. В следующем примере показаны оба варианта.
При использовании вывода типа тип массива определяется главным типом в списке литеральных значений. Главным типом является тип, к которому могут расширяться все другие типы в массиве. Если такой уникальный тип нельзя определить, то главным будет тип, до которого можно сузить все другие типы массива. Если ни один из указанных уникальных типов нельзя определить, главным типом будет Object . Например, если список значений для литерала массива содержит значения типов Integer , Long и Double , результирующий массив будет иметь тип Double . Поскольку Integer и Long расширяются только до Double , Double является главным типом. Для получения дополнительной информации см. Widening and Narrowing Conversions.
Вывод типа можно использовать только для массивов, определенных как локальные переменные в члене типа. Если явное определение типа отсутствует, массивы, определенные с литералами массива на уровне класса, имеют тип Object[] . Дополнительные сведения см. в разделе определение локального типа.
Обратите внимание, что в предыдущем примере определяется values как массив типа, Double хотя все литералы массива имеют тип Integer . Этот массив можно создать, так как значения в литерале массива могут расширяться до Double значений.
Можно также создать и заполнить многомерный массив с помощью вложенных литералов массива. Вложенные литералы массива должны иметь ряд измерений, которые соответствуют результирующему массиву. В следующем примере создается двухмерный массив целых чисел с помощью вложенных литералов массива.
При использовании вложенных литералов массива для создания и заполнения массива возникает ошибка, если число элементов в литералах вложенных массивов не совпадает. Ошибка также возникает, если вы явно объявили переменную массива так, чтобы число измерений не превышало литералы массива.
Точно так же, как и для одномерные массивов, при создании многомерного массива с вложенными литералами массива можно полагаться на определение типа. Выводимый тип является главным типом для всех значений во всех литералах массива для всех уровней вложенности. В следующем примере создается двухмерный массив типа Double[,] из значений типа Integer и Double .
Дополнительные примеры можно найти в статье How to: Initialize an Array Variable in Visual Basic (Практическое руководство. Инициализация переменной массива в Visual Basic).
Проход по массиву
При итерации по массиву вы обращаетесь к каждому элементу в массиве от самого низкого индекса к верхнему или от самого низкого. Как правило, используйте для. Next или For Each. Оператор Next для итерации элементов массива. Если вы не знакомы с верхними границами массива, можно вызвать Array.GetUpperBound метод, чтобы получить наибольшее значение индекса. Хотя наименьшее значение индекса почти всегда равно 0, можно вызвать Array.GetLowerBound метод, чтобы получить наименьшее значение индекса.
В следующем примере выполняется итерация по одномерным массиву с помощью For. Next инструкции.
В следующем примере выполняется перебор многомерного массива с помощью For. Next инструкции. Метод GetUpperBound имеет параметр, который определяет измерение. GetUpperBound(0) Возвращает самый верхний индекс первого измерения и GetUpperBound(1) возвращает наибольший индекс второго измерения.
В следующем примере используется объект For Each. Оператор Nextдля итерации одномерного массива и двумерного массива.
Размер массива
Размер массива является произведением длин всех его измерений. Он представляет собой общее число элементов, в данный момент содержащихся в массиве. Например, в следующем примере объявляется двухмерный массив с четырьмя элементами в каждом измерении. Как видно из выходных данных в примере, размер массива равен 16 (или (3 + 1) * (3 + 1).
Это обсуждение размера массива не применяется к массивам зубчатых размеров. Сведения о массивах немассивности и определении размера массива массивов см . в разделе массива массивов .
Размер массива можно определить с помощью свойства Array.Length. Длину каждого измерения многомерного массива можно узнать с помощью Array.GetLength метода.
Можно изменить размер переменной массива, назначив ей новый объект массива или используя инструкцию ReDim инструкции . В следующем примере оператор используется ReDim для изменения массива 100-element на массив 51-element.
Существует ряд особенностей, о которых следует помнить при работе с размером массива.
Примечания | |
---|---|
Длина измерения | Индекс каждого измерения основан на 0, что означает, что он находится в диапазоне от 0 до верхней границы. Таким образом, длина данного измерения больше, чем объявленная верхняя граница этого измерения. |
Ограничения длины | Длина каждого измерения массива ограничена максимальным значением Integer типа данных, которое равно Int32.MaxValue или (2 ^ 31)-1. Однако общий размер массива также ограничен доступной памятью в системе. При попытке инициализировать массив, размер которого превышает объем доступной памяти, среда выполнения создает исключение OutOfMemoryException . |
Размер и размер элемента | Размер массива не зависит от типа его элементов. Размер всегда представляет общее число элементов, а не число байтов, используемых в памяти. |
Потребление памяти | Небезопасно делать какие-либо предположения относительно способа хранения массива в памяти. Хранение зависит от разрядности платформы, поэтому один и тот же массив может занимать больше памяти в 64-разрядных системах, чем в 32-разрядных. В зависимости от конфигурации системы при инициализации массива среда CLR может использовать такие способы хранения, как упаковка элементов максимально близко друг к другу или выравнивание всех элементов по естественным аппаратным границам памяти. Кроме того, массив нуждается в хранении служебной информации, и размер этой информации возрастает при добавлении каждого измерения. |
Тип массива
Каждый массив имеет тип данных, который отличается от типа данных его элементов. Не существует единого типа данных, подходящего для всех массивов. Вместо этого тип данных массива определяется числом измерений ( рангом) массива и типом данных его элементов. Две переменные массива имеют один и тот же тип данных, только если они имеют одинаковый ранг и их элементы имеют один и тот же тип данных. Длины измерений массива не влияют на тип данных массива.
Каждый массив наследуется от класса System.Array, и вы можете объявить переменную типа Array , но не можете создать массив типа Array . Например, несмотря на то, что следующий код объявляет arr переменную как тип Array и вызывает Array.CreateInstance метод для создания экземпляра массива, тип массива доказывается на Object [].
Кроме того, оператор ReDim Array не может работать с переменной, объявленной с типом . По этим причинам, а для обеспечения безопасности типа рекомендуется объявлять каждый массив как конкретный тип.
Выяснить тип данных массива или его элементов можно несколькими способами.
- Можно вызвать GetType метод для переменной, чтобы получить Type объект, представляющий тип переменной во время выполнения. Объект Type содержит подробные сведения в своих свойствах и методах.
- Можно передать переменную в функцию, TypeName чтобы получить String с именем типа времени выполнения.
В следующем примере GetType TypeName для определения типа массива вызывается метод и функция. Тип массива — Byte(,) . Обратите внимание, что Type.BaseType свойство также указывает, что базовый тип массива байтов является Array классом.
Массивы как возвращаемые значения и параметры
Чтобы вернуть массив из процедуры Function , укажите тип данных массива и число измерений в качестве типа возвращаемого значения оператора Function. Внутри функции объявите локальную переменную массива с тем же числом измерений и типом данных. В оператор Return включите локальную переменную массива без скобок.
Чтобы задать массив в качестве параметра процедуры Sub или Function , определите параметр как массив с указанными типом данных и количеством измерений. В вызове процедуры передайте переменную массива с тем же типом данных и количеством измерений.
В следующем примере GetNumbers функция возвращает Integer() одномерный массив типа Integer . Процедура ShowNumbers принимает аргумент Integer() .
В следующем примере GetNumbersMultiDim функция возвращает Integer(,) , двухмерный массив типа Integer . Процедура ShowNumbersMultiDim принимает аргумент Integer(,) .
Массивы массивов
Иногда структура данных в приложении является двухмерной, но не прямоугольной. Например, массив можно использовать для хранения данных о высокой температуре каждого дня месяца. Первое измерение массива представляет месяц, но второе измерение представляет количество дней, а число дней в месяце является неравномерным. Немассивный массив, который также называется массивом массивов, предназначен для таких сценариев. Немассивный массив — это массив, элементы которого также являются массивами. Массив массивов и каждый элемент в нем могут иметь одно или несколько измерений.
В следующем примере используется массив месяцев, каждый элемент которого является массивом дней. В примере используется массив массива, поскольку разные месяцы имеют разное количество дней. В примере показано создание массива массивов, присвоение ему значений, а также извлечение и отображение его значений.
Массив массива является одномерным массивом, элементы которого содержат массивы. Таким образом, Array.Length свойство и Array.GetLength(0) метод возвращают количество элементов в одномерном массиве и выдают исключение, Array.GetLength(1) IndexOutOfRangeException так как массив массива не является многомерным. Число элементов в каждом подмассиве определяется путем извлечения значения свойства каждого подмассива Array.Length . В следующем примере показано, как определить количество элементов массива массивов.
Массивы нулевой длины
Visual Basic отличает неинициализированный массив (массив, значение которого равно Nothing ) и массив нулевой длины или пустой массив (массив без элементов). Неинициализированный массив — это тот, который не был измерен или имел присвоенные ему значения. Вот несколько примеров.
Массив нулевой длины объявляется с измерением-1. Вот несколько примеров.
Массив нулевой длины может потребоваться создать в указанных ниже случаях.
без риска возникновения NullReferenceException исключения код должен обращаться к членам Array класса, например Length или Rank , или вызвать функцию Visual Basic, например UBound .
Вы хотите, чтобы ваш код был простым, не требуя проверки в Nothing качестве специального случая.
Код взаимодействует с интерфейсом API, который требует передачи массива нулевой длины в одну или несколько процедур или возвращает массив нулевой длины из одной или нескольких процедур.
Разделение массива
В некоторых случаях может потребоваться разделить один массив на несколько массивов. Это включает определение точки или точек, в которых массив должен быть разделен, а затем спиттинг массив в два или более отдельных массива.
В этом разделе не рассматривается разделение одной строки на массив строк, основанный на каком-либо разделителе. Сведения о разбиении строки см. в описании String.Split метода.
Ниже приведены наиболее распространенные критерии разделения массива.
Количество элементов в массиве. Например, может потребоваться разделить массив больше, чем заданное число элементов, на несколько приблизительно равных частей. Для этой цели можно использовать значение, возвращаемое Array.Length Array.GetLength методом или.
Значение элемента, которое служит разделителем, указывающим место разделения массива. Можно выполнить поиск определенного значения, вызвав Array.FindIndex Array.FindLastIndex методы и.
После определения индекса или индексов, на которых массив должен быть разделен, можно создать отдельные массивы, вызвав Array.Copy метод.
В следующем примере массив разбивается на два массива приблизительно равного размера. (Если общее число элементов массива нечетное, первый массив содержит еще один элемент, чем второй.)
В следующем примере массив строк разбивается на два массива на основе наличия элемента, значение которого равно "zzz", которое служит разделителем массива. Новые массивы не включают элемент, содержащий разделитель.
Соединение массивов
Можно также объединить несколько массивов в один массив большего размера. Для этого также используется Array.Copy метод.
В этом разделе не обсуждается объединение массива строк в одну строку. Сведения о присоединении массива строк см. в описании String.Join метода.
Перед копированием элементов каждого массива в новый массив необходимо убедиться, что массив был инициализирован так, чтобы он был достаточно большим для размещения нового массива. Это можно сделать одним из двух способов.
- Используйте ReDim Preserve инструкцию для динамического расширения массива перед добавлением в него новых элементов. Это самый простой способ, но это может привести к снижению производительности и чрезмерному потреблению памяти при копировании больших массивов.
- Вычислите общее число элементов, необходимых для нового большого массива, а затем добавьте в него элементы каждого исходного массива.
В следующем примере используется второй подход к добавлению четырех массивов с десятью элементами в один массив.
Поскольку в этом случае исходные массивы невелики, можно также динамически расширять массив по мере добавления элементов каждого нового массива в него. Эту задачу решает следующий код.
Коллекции в качестве альтернативы массивам
Массивы удобнее всего использовать для создания фиксированного числа строго типизированных объектов и работы с ними. Коллекции предоставляют более гибкий способ работы с группами объектов. В отличие от массивов, требующих явного изменения размера массива ReDim инструкцией, коллекции растут и сжимаются динамически в соответствии с потребностями приложения.
при использовании ReDim для переизмерения массива Visual Basic создает новый массив и освобождает предыдущий. Это занимает время выполнения. Таким образом, если количество элементов, с которыми вы работаете, часто меняются, или вы не можете предсказать максимальное количество элементов, вы обычно получаете лучшую производительность, используя коллекцию.
Некоторые коллекции допускают назначение ключа любому объекту, который добавляется в коллекцию, чтобы в дальнейшем можно было быстро извлечь связанный с ключом объект из коллекции.
какие операции я могу сделать на arr1 и arr2 и сохранить результат в arr3 такой, что:
к сожалению, тип массива в VB6 не имел всех функций razzmatazz. Вам в значительной степени придется просто перебирать массивы и вставлять их вручную в третий
предполагая, что оба массива имеют одинаковую длину
Обновлено: исправлен код. Извините за предыдущую версию багги. Мне потребовалось несколько минут, чтобы получить доступ к компилятору VB6, чтобы проверить его.
эта функция будет делать, как предложил JohnFx и учитывать различные длины на массивах
я попробовал код, указанный выше, но он дал мне ошибку 9. Я сделал этот код, и он отлично работал для моих целей. Я надеюсь, что и другие найдут его полезным.
он работает, если Lbound отличается от 0 или 1. Вы Redim один раз в начале
мой предпочтительный способ немного длинный, но имеет некоторые преимущества перед другими ответами:
- он может объединить неопределенное количество массивов сразу
- он может комбинировать массивы с не-массивами (объектами, строками, целыми числами и т. д.)
- он учитывает возможность того, что один или несколько массивов могут содержать объекты
- Это позволяет пользователю выбрать базу нового массива (0, 1 и т. д.)
к сожалению, нет возможности добавлять / объединять / вставлять / удалять элементы в массивах с помощью VBA, не делая этого по элементам, в отличие от многих современных языков, таких как Java или Javascript .
можно использовать split и join сделать это, как показал предыдущий ответ, но это медленный метод, и он не является общим.
для моего личного использования, я реализовал splice функции для массивов 1D, подобных Javascript или Java. splice вам массив и необязательно удалять некоторые элементы из заданной позиции, а также необязательно вставлять массив в эту позицию
вот версия, которая использует объект коллекции для объединения двух 1-d массивов и передачи их в 3-й массив. Не работает для многомерных массивов.
Какие операции я могу выполнить для arr1 и arr2 и сохранить результат в arr3, чтобы:
ОТВЕТЫ
Ответ 1
К сожалению, тип массива в VB6 не обладал множеством функций razzmatazz. Вам в значительной степени придется просто перебирать массивы и вставлять их вручную в третью
Предполагая, что оба массива имеют одинаковую длину
Обновлено: Исправлен код. Извините за предыдущую ошибку. Мне потребовалось несколько минут, чтобы получить доступ к компилятору VB6, чтобы проверить его.
Ответ 2
Ответ 3
Эта функция будет делать, как предложил JohnFx, и допускать различную длину на массивах
Ответ 4
Я попробовал приведенный выше код, но для меня это дало ошибку 9. Я сделал этот код, и он отлично работал для моих целей. Я надеюсь, что другие считают это полезным.
Ответ 5
Работает, если Lbound отличается от 0 или 1. Вы переиздаете один раз при запуске
Ответ 6
Мой предпочтительный способ немного длинный, но имеет некоторые преимущества по сравнению с другими ответами:
- Он может объединить неограниченное количество массивов сразу
- Он может объединять массивы с не-массивами (объекты, строки, целые числа и т.д.).
- Он учитывает возможность того, что один или несколько массивов могут содержать объекты
- Он позволяет пользователю выбирать базу нового массива (0, 1 и т.д.).
Ответ 7
К сожалению, нет способа добавить/объединить/вставить/удалить элементы в массивах, используя VBA, не делая это элемент за элементом, в отличие от многих современных языков, таких как Java или Javascript .
Для этого можно использовать split и join , как показано в предыдущем ответе, но это медленный метод, и он не является универсальным.
Для личного использования я реализовал функции splice для одномерных массивов, аналогично Javascript или Java. splice получить массив и при желании удалить некоторые элементы из заданной позиции, а также при необходимости вставить массив в этой позиции
Ответ 8
Здесь версия, которая использует объект коллекции, чтобы объединить два 1-го массива и передать их в 3-й массив. Не работает для многомерных массивов.
Ответ 9
После решения @johannes, но слияние без потери данных (в нем отсутствовали первые элементы):
Объявляете третий массив с длинной суммой этих двух
Или копимемори или перебором пихаете туда элементы
В чем проблема?
Объявляете третий массив с длинной суммой этих двух
Или копимемори или перебором пихаете туда элементы
В чем проблема?
Копимемори это функция АПИ
При разработке приложений довольно часто встречается простая задача пересылки N последовательных байтов из одной области оперативной памяти в другую. В VB проблема возникает, когда такая область памяти определена не именем переменной, а в виде адреса (указателя — Pointer). К сожалению, встроенные средства VB не позволяют работать с адресами, а порой это крайне необходимо.
Так, некоторые функции Win API, используемые для получения информации о ресурсах системы (например, VerQueryValue), возвращают в качестве параметра адрес области памяти FiAddr&, где лежит искомая информация. Но как переписать эти данные, к примеру, в целочисленный массив для дальнейшей обработки в среде VB? Это можно сделать с помощью функций Win API.
В составе Win16 API для этого имелась функция HMemCpy:
Листинг 1.
Она появилась только в расширенном варианте функций в Windows 3.1 (в версии 3.0 ее не было), а в пакете VB 3.0 ее описание было приведено только в файле WIN31WH.HLP.
Что же касается Win32 API, то в описании WIN32API.TXT для VB 4.0 и 5.0 о функции HMemCpy или ее аналоге даже и не упоминается. Более того, в книге Дэна Эпплмана по Win32 API, на которую мы часто ссылаемся (о ней мы писали в Совете 133), ничего не говорится о подобной функции. Однако, поскольку такая функция действительно очень нужна, Дэн предлагает использовать процедуру agCopyData из его собственной библиотеки APIGI32.DLL, которая приводится на прилагаемом компакт-диске.
Все это выглядит весьма странно. Более тщательный поиск, проведенный с помощью специалиста московского отделения Microsoft Юрия Томашко, увенчался успехом — в Win32 есть функция копирования байтов CopyMemory и ее описание появилось в VB 6.0 в файле WIN32API.TXT. Почему Microsoft скрывает от пользователей VB 4.0 и 5.0 ее существование, и почему Дэн Эпплман хранит эту тайну — можно только гадать. Кстати, настоящее имя функции в библиотеке KERNEL32 — RtlMoveMemory:
Листинг 2.
Вот типичный пример применения этой функции:
Листинг 3.
CopyMemory можно использовать для создания очень полезных функций преобразования типов данных (см. Совет 172), а также для ускорения в сотни и даже тысячи раз выполнения операций, реализуемых традиционными средствами VB. Например, для копирования целых массивов или их фрагментов:
Листинг 4.
Читайте также: