mail mail

Объединение строк в двумерном массиве

Эта функция позволяет осуществить объединение строк в двумерном массиве.

функция получает в качестве параметров исходный массив, и номер столбца ComparedColumn,
по которому осуществляется сравнение строк
---------------------------------------------
для совпадающих строк:
- суммируются значения в столбцах, перечисленных через запятую в переменной ColumnsForSum
- соединяются (через разделитель JoinSeparator) значения в столбцах,
перечисленных через запятую в переменной ColumnsForJoin
---------------------------------------------
функция возвращает новый массив (возможно, с меньшей размерностью по вертикали)

Function JoinedArray(ByVal arr As Variant, ByVal ComparedColumn As Long, _
                     Optional ByVal ColumnsForSum As String, Optional ByVal ColumnsForJoin As String, _
                     Optional ByVal JoinSeparator As String = ", ") As Variant
    '     осуществляет объединение строк в массиве
   '     получает в качестве параметров исходный массив, и номер столбца ComparedColumn,
   '     по которому осуществляется сравнение строк
   '     ---------------------------------------------
   '     для совпадающих строк:
   '     - суммируются значения в столбцах, перечисленных через запятую в переменной ColumnsForSum
   '     - соединяются (через разделитель JoinSeparator) значения в столбцах,
   '       перечисленных через запятую в переменной ColumnsForJoin
   '     ---------------------------------------------
   '     функция возвращает новый массив (возможно, с меньшей размерностью по вертикали)


    On Error Resume Next
    If Not IsArray(arr) Then MsgBox "Это не массив!", vbCritical: Exit Function
    If ComparedColumn > UBound(arr, 2) Then MsgBox "Нет такого столбца в массиве!", vbCritical: Exit Function
    If ComparedColumn < LBound(arr, 2) Then MsgBox "Нет такого столбца в массиве!", vbCritical: Exit Function

    For i = LBound(arr, 1) To UBound(arr, 1)
        If arr(i, ComparedColumn) <> "" Then
            For j = i + 1 To UBound(arr, 1)
                If arr(j, ComparedColumn) = arr(i, ComparedColumn) Then
                    ' для последующего удаления этой строки из массива
                   arr(j, ComparedColumn) = Empty    ' затираем значение в сравниваемом столбце

                    ' суммируем строки - результат в верхнюю строку
                   For Each col In Split(ColumnsForSum, ",")
                        nCol = Val(col)
                        If nCol > 0 And nCol <= UBound(arr, 2) And nCol <> ComparedColumn Then
                            arr(i, nCol) = Val(Replace(arr(i, nCol), ",", ".")) _
                                         + Val(Replace(arr(j, nCol), ",", "."))
                        End If
                    Next

                    ' сцепляем строки - результат в верхнюю строку
                   For Each col In Split(ColumnsForJoin, ",")
                        nCol = Val(col)
                        If nCol > 0 And nCol <= UBound(arr, 2) And nCol <> ComparedColumn Then
                            If Len(Trim(arr(j, nCol))) > 0 Then
                                arr(i, nCol) = Trim(arr(i, nCol)) & JoinSeparator & Trim(arr(j, nCol))
                            End If
                        End If
                    Next
                End If
            Next j
        End If
    Next i

    ' удаляем ненужные (пустые) строки
   Dim iCount As Long    ' кол-во непустых строк
   For i = LBound(arr) To UBound(arr)
        iCount = iCount - (arr(i, ComparedColumn) <> "")
    Next i

    ' формируем новый массив
   ReDim narr(LBound(arr, 1) To iCount + LBound(arr, 1) - 1, LBound(arr, 2) To UBound(arr, 2))

    iCount = LBound(narr)    ' счётчик записей
   For i = LBound(arr, 1) To UBound(arr, 1)
        If arr(i, ComparedColumn) <> "" Then
            For j = LBound(arr, 2) To UBound(arr, 2)
                narr(iCount, j) = arr(i, j)
            Next j
            iCount = iCount + 1
        End If
    Next i

    JoinedArray = narr
End Function

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

Sub ПримерИспользования()
    ' отключаем обновление экрана
   Application.ScreenUpdating = False
    ' считываем массив с листа - в него попадут все заполненные строки
   Массив = Range([A1], Range("A" & Rows.Count).End(xlUp)).Resize(, 3).Value

    ' объединяем уникальные, суммируя данные в столбцах 2 и 3
   arr = JoinedArray(Массив, 1, "2,3")

    Range("e:g").ClearContents    ' очистка содержимого столбцов E F G
   ' заносим массив на лист, начиная с ячейки e1
   Range("e1").Resize(UBound(arr, 1), UBound(arr, 2)).Value = arr
End Sub

ВложениеРазмер
JoinedArray.xls870 КБ

Комментарии

Настройки просмотра комментариев

Выберите нужный метод показа комментариев и нажмите "Сохранить установки".

спасибо за вразумительный ответ, а то моя голова была бы совсем сломана дальнейшими безуспешными попытками объединения диапазонов с разных листов)))

Вы путаете понятия "массив" и "диапазон ячеек". Это совершенно разные вещи.
Моя функция работает с массивами. Массив - это набор значений в памяти компьютера, безотносительно к каким-либо ячейкам или листам.
И функции неважно, откуда взят этот массив, - главное, чтобы он был двумерным.

Массив не может находиться на листе Excel.
На листе Excel может быть диапазон ячеек, а вот значения из этого диапазона ячеек могут быть считаны в массив.

То, что пытаетесь сделать вы - при помощи Union(лист1.массив;лист2.массив), в принципе работать не будет.
И виновата в этом не моя функция, а неверное использование функции Union:
Нельзя объединять диапазоны с разных листов:

Sub test()
    Dim ra As Range: Set ra = Union(Лист1.[a1:d5], Лист2.[a1:d5])
End Sub

Даже если бы вы каким-то образом объединили 2 диапазона ячеек, то моя функция не смогла бы обработать результат,
поскольку результатом был бы не двумерный массив, а массив массивов.

Совет:
1) в цикле считайте данные с каждого листа в массив
2) объедините все массивы в один при помощи функции CombineArrays
http://excelvba.ru/code/CombineArrays
3) результат поместите на нужный лист

Здравствуйте! Поправьте если ошибаюсь: функция работает только если исходный массив и преобразованный находятся на одном листе. Есть ли возможность использовать в качестве исходного массива - Union(лист1.массив;лист2.массив) а преобразованный поместить на лист3 ?

Так пробовали?

  ' объединяем уникальные, суммируя данные по столбцам 2 и 3,
 ' и соединяя данные через запятую в столбцах 5, 8 и 9
  arr = JoinedArray(Массив, 1, "2,3", "5,8,9")

Через запятую значения не расставляет. Как добиться этого?

Этот макрос не предназначен для таких больших массивов.
А тысячами строк он работает нормально, и даже ни десятках тысяч строк его можно применять (хотя, пожалуй, он будет подтормаживать)
А в вашем случае (сотни тысяч строк) надо применять совершенно другие алгоритмы обработки.
Могу посоветовать использовать встроенные средства Excel
(поскольку и версия Excel у вас не ниже 2007-й, да и массbm изначально ни листе находится)

Пытаюсь загнать диапазон в массив Массив = Range("A2:L359731").Value
В ответ получаю "аут оф мемори"

Отправить комментарий

Содержание этого поля является приватным и не предназначено к показу.
CAPTCHA
Подтвердите, пожалуйста, что вы - человек:
8 + 9 =
Решите эту простую математическую задачу и введите результат. Например, для 1+3, введите 4.