Как посчитать повторяющиеся записи в OpenOffice/LibreOffice BASIC?
У меня огромное количество данных на многих листах в LibreOffice - ADDRESS
колонна и DATA
столбец - и я хотел бы посчитать, сколько раз каждый адрес встречается, положить в NUM_ADDR
колонка. Например:
ADDR | DATA | NUM_ADDR
00000000bbfe22d0 | 876d4eb163886d4e | 1
00000000b9dfffd0 | 4661bada6d4661ba | 1
00000000b9dfc3d0 | 5d4b40b4705d4b40 | 1
00000000b9def7d0 | 8f8570a5808f8570 | 1
00000000b9de17d0 | 63876d4eb163886d | 1
00000000b9dddfd0 | 6d4eb163886d4eb1 | 3
00000000b9dddfd0 | 705d4b40b4705d4b |
00000000b9dddfd0 | b4705d4b40b4705d |
00000000b7df83d0 | 40b4705d4b40b470 | 1
00000000b7d607d0 | 705d4b40b4705d4b | 1
...
Делая вещи вручную, я использовал COUNTIF
функция на каждом адресе, но я обнаружил, что макрос сэкономит время в долгосрочной перспективе. Вот фрагмент того, что у меня есть, учитывая, что предыдущая функция уже определила длину (количество строк) данных, хранящихся в RowCounter
:
Dim CountedAddr(RowCounter, RowCounter) as String
Dim CountedAddrPtr as Integer
Dim CurrentCell as Object
Dim i as Integer
CountedAddrPtr = 0
' Populate CountedAddr array
For i = 1 to RowCounter-1
CurrentCell = CurrentSheet.getCellByPosition(0, i)
If Not CurrentCell.String In CountedAddr(?) Then
CurrentSheet.getCellByPosition(2, i).Value = 1 ' for debugging
CountedAddr(CountedAddrPtr, 0) = CurrentCell.String
CountedAddrPtr = CountedAddrPtr + 1
Else
CurrentSheet.getCellByPosition(2, i).Value = 0 ' for debugging
EndIf
Next
' For each unique address, count number of occurances
For i = 0 to UBound(CountedAddr())
For j = 1 to RowCounter-1
If CurrentSheet.getCellByPosition(0, j).String = CountedAddr(i, 0) Then
CountedAddr(i, 1) = CountedAddr(i, 1)+1
EndIf
Next
Next
' Another function to populate NUM_ADDR from CountedAddr array...
Итак, мой первый вопрос: как мы можем определить, находится ли элемент (адрес в текущей ячейке) в CountedAddr
массив (см. (?)
выше)? Во-вторых, есть ли гораздо более эффективный способ достижения второго блока кода? К сожалению, об сортировке не может быть и речи, поскольку хронология адресов и данных образует нечто временное. В-третьих, является ли весь шебанг глупым способом решения этой проблемы?
Большое спасибо от аппаратного dood на программную задачу!
1 ответ
Объекты словарного типа, такие как VB6 Collection, эффективны для поиска элементов, потому что он находит ключ напрямую, а не просматривает длинный массив. наш countedAddrs
Коллекция ниже будет хранить счетчик для каждого адреса.
Sub CountAddrs
Dim countedAddrs As New Collection
Dim oCurrentSheet As Object
Dim oCurrentCell As Object
Dim currentAddr As String
Dim i As Integer
Dim newCount As Integer
Dim rowCounter As Integer
Const ADDR_COL = 0
Const COUNT_COL = 2
oCurrentSheet = ThisComponent.CurrentController.ActiveSheet
rowCounter = 11
' Populate countedAddrs array.
For i = 1 to rowCounter - 1
oCurrentCell = oCurrentSheet.getCellByPosition(ADDR_COL, i)
currentAddr = oCurrentCell.String
If Contains(countedAddrs, currentAddr) Then
' Increment the count.
newCount = countedAddrs.Item(currentAddr) + 1
countedAddrs.Remove(currentAddr)
countedAddrs.Add(newCount, currentAddr)
oCurrentSheet.getCellByPosition(COUNT_COL, i).Value = newCount ' for debugging
Else
countedAddrs.Add(1, currentAddr)
oCurrentSheet.getCellByPosition(COUNT_COL, i).Value = 1 ' for debugging
EndIf
Next
End Sub
Этот код требует следующую вспомогательную функцию. В большинстве языков словарные объекты имеют эту встроенную функциональность, но Basic довольно прост.
' Returns True if the collection contains the key, otherwise False.
Function Contains(coll As Collection, key As Variant)
On Error Goto ErrorHandler
coll.Item(key)
Contains = True
Exit Function
ErrorHandler:
Contains = False
End Function