Сравнение массиов в макросе

Автор joshua, 31 мая 2017, 10:43

0 Пользователи и 1 гость просматривают эту тему.

joshua

Господа подскажите пожалуйста, как эффективно сравнить два массива данных.
Есть два одномерных массива oAllData1 и oAllData2 , берутся из соответствующих диапазонов A1:A10 и  B1:B12 к примеру.
Нужно найти все элементы из массива oAllData2, которых нет в массиве oAllData1 и вывести их в отдельный массив

Ключевой аспект это скорость выполнения, так как элементов в обоих массивах может быть и 10 000 и 30 000

Sub GetAndSetData
Dim oRange1 'Основной диапазон
Dim oRange2 'Основной диапазон
Dim oSheet 'Первый лист
Dim oAllData1  'Массив, содержащий данные
Dim oAllData2  'Массив, содержащий данные

Dim s As String 'Основная строковая переменная
Dim i As Integer 'Основная индексная переменная
oSheet = ThisComponent.Sheets(0)
oRange1 = oSheet.getCellRangeByName("A1:A10")
oRange1 = oSheet.getCellRangeByName("B1:B12")
oAllData1 = oRange1.getDataArray()
oAllData2 = oRange2.getDataArray()
??? что дальше
End Sub

economist

1) Если важна скорость, то формулами массива в ODS будет быстрее, чем на StarBasic.

2) Если нужны преобразования элементов "на лету" - макрос будет быстрее.

3) Если нужны преобразования (группировки, вычисления, подсчёты) в результирующем наборе - то правильнее именовать диапазоны, подключиться к ODS как к базе данных ODB и выполнить типовой SQL-запрос по возврату уникальностей из таблицы oAllData2.
Руб. за сто, что Питоньяк
Любит водку и коньяк!
Потому что мне, без оных, -
Не понять его никак...

joshua

Цитата: economist от 31 мая 2017, 10:061) Если важна скорость, то формулами массива в ODS будет быстрее, чем на StarBasic.
Что такое ODS?

mikekaganski

Sub SortRange(oCellRange)
 REM An array of sort fields determines the columns that are
 REM sorted. This is an array with two elements, 0 and 1.
 REM To sort on only one column, use:
 REM Dim oSortFields(0) As New com.sun.star.util.SortField
 Dim oSortFields(0) As New com.sun.star.util.SortField

 REM The sort descriptor is an array of properties.
 REM The primary property contains the sort fields.
 Dim oSortDesc(0) As New com.sun.star.beans.PropertyValue

 REM Select the range to sort.
 REM The only purpose would be to emphasize the sorted data.
 'ThisComponent.getCurrentController.select(oCellRange)

 REM Sort by range's first column ascending.
 oSortFields(0).Field = oCellRange.RangeAddress.StartColumn
 oSortFields(0).SortAscending = TRUE

 REM Setup the sort descriptor.
 oSortDesc(0).Name = "SortFields"
 oSortDesc(0).Value = oSortFields

 REM Sort the range.
 oCellRange.Sort oSortDesc
End Sub

Sub GetAndSetData
 time1 = now
 Dim oRange As Object'Основной диапазон
 Dim oSheet As Object 'Первый лист
 Dim oAllData1() 'Массив, содержащий данные
 Dim oAllData2() 'Массив, содержащий данные

 oSheet = ThisComponent.Sheets(0)
 oRange = oSheet.getCellRangeByName("A1:A30000")
 SortRange oRange
 oAllData1 = oRange.getDataArray()
 oRange = oSheet.getCellRangeByName("B1:B30000")
 SortRange oRange
 oAllData2 = oRange.getDataArray()
 
 Dim i As Integer, j As Integer, jMax As Integer 'Основная индексная переменная
 Dim oResultData(30000) 'Массив, содержащий данные
 Dim n As Integer : n = LBound(oResultData)

 j = LBound(oAllData2) : jMax = Ubound(oAllData2)
 For i = LBound(oAllData1) To Ubound(oAllData1)
   If (i > LBound(oAllData1)) Then
     If (oAllData1(i)(0) = oAllData1(i-1)(0)) Then
       GoTo Continue
     End If
   End If
   While ((oAllData2(j)(0) < oAllData1(i)(0)) And (j < jMax))
     j=j+1
   Wend

   If (oAllData2(j)(0) = oAllData1(i)(0)) Then
     oResultData(n) = oAllData1(i)(0)
     n = n + 1
     If (j < jMax) Then j=j+1
   End If
Continue:
 Next i
 ReDim Preserve oResultData(LBound(oResultData) To n)
 print Format(now - time1, "[ss]")
End Sub


У меня даёт 2-3 с на случайных числах
(я сортирую данные "на месте")
С уважением,
Михаил Каганский

economist

joshua - ODS это единственный формат файла электронных таблиц OpenOffice|LibreOffice Calc, в котором макросы будут работать предсказуемо. В форматах файлов xls... это не так.
Руб. за сто, что Питоньяк
Любит водку и коньяк!
Потому что мне, без оных, -
Не понять его никак...

joshua

Спасибо, только у меня почему то ошибка вылезает :o

mikekaganski

Хм. AOO.

Sub SortRange(oCellRange)
  REM An array of sort fields determines the columns that are sorted
  Dim oSortFields(0) As New com.sun.star.util.SortField

  REM The sort descriptor is an array of properties.
  REM The primary property contains the sort fields.
  Dim oSortDesc(0) As New com.sun.star.beans.PropertyValue

  REM Sort by range's first column ascending.
  oSortFields(0).Field = 0
  oSortFields(0).SortAscending = TRUE

  REM Setup the sort descriptor.
  oSortDesc(0).Name = "SortFields"
  oSortDesc(0).Value = oSortFields

  REM Sort the range.
  oCellRange.Sort oSortDesc
End Sub

Sub GetAndSetData
  time1 = now
  Dim oRange As Object'Основной диапазон
  Dim oSheet As Object 'Первый лист
  Dim oAllData1() 'Массив, содержащий данные
  Dim oAllData2() 'Массив, содержащий данные

  oSheet = ThisComponent.Sheets(0)
  oRange = oSheet.getCellRangeByName("A1:A30000")
  SortRange oRange
  oAllData1 = oRange.getDataArray()
  oRange = oSheet.getCellRangeByName("B1:B30000")
  SortRange oRange
  oAllData2 = oRange.getDataArray()

  Dim s As String 'Основная строковая переменная
  Dim i As Integer, j As Integer, jMax As Integer 'Основная индексная переменная
  i = UBound(oAllData1) - LBound(oAllData1)
  j = UBound(oAllData2) - LBound(oAllData2)
  If (j<i) Then i = j
  Dim oResultData(0 to i) 'Массив, содержащий данные
  Dim n As Integer : n = LBound(oResultData)

  j = LBound(oAllData2) : jMax = Ubound(oAllData2)
  For i = LBound(oAllData1) To Ubound(oAllData1)
    If (i > LBound(oAllData1)) Then
      If (oAllData1(i)(0) = oAllData1(i-1)(0)) Then GoTo Continue
    End If
    While ((oAllData2(j)(0) < oAllData1(i)(0)) And (j < jMax))
      j=j+1
    Wend

    If (oAllData2(j)(0) = oAllData1(i)(0)) Then
      oResultData(n) = oAllData1(i)(0)
      n = n + 1
      If (j < jMax) Then j=j+1
    End If
Continue:
  Next i
  ReDim Preserve oResultData(0 To n-1)
  print Format(now - time1, "[ss]")
End Sub


Первая ошибка - моя. Я думал, что oSortFields(0).Field должна содержать номер столбца не в диапазоне, а на листе. Но это не имеет отношения к Вашему сообщению об ошибке. Просто второй столбец не сортировался, так что результат был бы корявым.

Вторая ошибка - AOO. Он не умеет получать LBound от массива внутри ReDim для этого массива. Отсюда и проблема.
С уважением,
Михаил Каганский

joshua

Цитата: mikekaganski от 31 мая 2017, 12:28Первая ошибка - моя. Я думал, что oSortFields(0).Field должна содержать номер столбца не в диапазоне, а на листе. Но это не имеет отношения к Вашему сообщению об ошибке. Просто второй столбец не сортировался, так что результат был бы корявым.

А что тогда надо написать вместо oSortFields(0).Field = oCellRange.RangeAddress.StartColumn ?

mikekaganski

Я же исправленный код вроде дал?
С уважением,
Михаил Каганский

joshua

А да, действительно код исправленный. Но мне кажется он все равно немного не то считает.
Ведь новый массив должен состоять из значений второго массива, которые не встречаются в первом массиве.
Вот например таблица. Поидее новый массив должен состоять из трех значений
Антилопа
Майский жук
Мандарин

Но он состоит совсем из других значений



mikekaganski

#10
Так. Не обращайте на меня внимания. Я тут совсем не то делал, что требовалось. Выбирал *совпадающие*.
С уважением,
Михаил Каганский

joshua

Понял, столбцы переставил
Я попробовал с цифрами
в первом столбце
1 2 3 4 5 6 7 8 9 10 11 12 13
во втором
1 2 3 4 5 6 7 8 9 10
oResultData поидее должеть стать 11 12 13
а получается что oResultData(0) = 1 2 3 4 5 6 7 ...

joshua

Цитата: mikekaganski от 31 мая 2017, 13:30Так. Не обращайте на меня внимания. Я тут совсем не то делал, что требовалось. Выбирал *совпадающие*.
))) Ну все равно спасибо тебе, теперь по-крайней мере есть эскиз, попробую что  нибудь из него получить)
Только я не понял что делает Sub SortRange(oCellRange)? сортирует каждый столбец по возрастанию?

mikekaganski

Да, сортирует. Я же не знал, что они уже сортированные и уникальные. Можно было и проще при таких условиях.
С уважением,
Михаил Каганский

joshua

Цитата: mikekaganski от 31 мая 2017, 13:51Да, сортирует. Я же не знал, что они уже сортированные и уникальные. Можно было и проще при таких условиях.
Да не они на сам деле могут разные быть, это я для примера там взял. Так что сортировка пригодиться.