Страницы: Пред. 1 2 3 4 След.
RSS
Удаление дубликатов Collection vs. Dictionary
 
bedvit, да, сортировать можно. Да, все верно.
 
Пока самый быстрый способ это
Код
.Sort + RemoveDuplicates
, дополнен пример из 18го сообщения -1,8 сек.
Но это через Лист/Range Excel со своими издержками. Можно написать свою библиотеку, думаю будет быстрее :)
«Бритва Оккама» или «Принцип Калашникова»?
 
bedvit, спасибо за пример.
Но этот способ нельзя использовать если количество уникальных значений больше строк в Excel.
 
Цитата
AB1 написал:
Единственная проблема - строки сокращаются до 255 символов.
К сожалению, пока решить не удалось.

В schema.ini указал тип Memo, для ImportMixedTypes установил значение Majority Type, TypeGuessRows установил на 0, добавил IMEX=2, подключил Microsoft ActiveX Data Objects 6.1, но тщетно - все текстовые значения урезаются до 255 символов  :)  
 
Делайте по моему описанию - медленно, сердито, но надёжно :)
Да не так и медленно..
 
Hugo, пишет хороший вариант, сделайте загрузку файла CSV, обработку повторов в строках и выгрузку в файл CSV в одном блоке команд. Вы же загружаете и выгружаете CSV построчно?
«Бритва Оккама» или «Принцип Калашникова»?
 
Я чуть иначе предлагал - читаем и пишем файлы сразу параллельно построчно. Причём читать можно кучей сразу все, а писать в один.
 
Hugo, в связи с тем что файл будет один (насколько я понял), ваша мысль идентична моей фразе (писать из начального файла в конечный построчно, проверяя строки на уникальность) :)
«Бритва Оккама» или «Принцип Калашникова»?
 
Цитата
Hugo написал:
читаем и пишем файлы сразу параллельно построчно.
Лишь бы памяти хватило ;)  Пусть средняя длина строки 256 в ANSI на 10000000 строк будет почти 2,4 Гбайта данных.
 
А зачем столько памяти? Если построчно читать...
А какие ключи нужно будет хранить в словаре/коллекции - об этом пока никто не говорил.
 
Цитата
Hugo написал:
А какие ключи нужно будет хранить в словаре/коллекции - об этом пока никто не говорил.
Ну, если самый страшный случай - именно строки больше 255 символов, то можно хранить в коллекции/словаре хэш строк, тогда будет не так страшно по памяти.
 
Почитал про уникальность хэшей... :(
 
Цитата
Hugo написал:
уникальность хэшей... :(
А что расстроило?
 
Цитата
   У каждого алгоритма хэширования есть вероятность коллизий из-за ограничения длинны генерируемой строки.
Это неотъемлемая часть собственно хеширования. Если нужно чтобы дубликаты были невозможны в принципе, длина хэша должна быть не меньше длины исходного файла.
хотя
Цитата
SHA1 достаточно уникальна. Коллизии у MD5 ищутся за минуты, про SHA1 и тем более SHA512 такого не слышал.
но всёж опаска есть... на гигабайты возможно похожих строк то как-то сыкотно...
Но пока про ключи так ничего и не известно.
 
AB1, а ваша программа не умеет группировать данные при выгрузке в файл CSV? (Обычный функционал для среднего уровня программы). Или хотя бы сортировать перед выгрузкой. Будет значительно проще удалять дубликаты, не нужно будет словарей, коллекций и 2,4 Гбайта данных  :)
Скрытый текст

А какими инструментами вы сейчас это перелапачиваете?
«Бритва Оккама» или «Принцип Калашникова»?
 
Нашел в чем загвоздка с ADO - если считывать данные без GROUP BY, то строки (>255) не укорачиваются, а если использовать GROUP BY, то происходит лимитирование  :)  
 
Цитата
Андрей VG написал:
Лишь бы памяти хватило
Если речь идет про память компьютера, то установлено 64 Гб.
 
Цитата
AB1 написал:
установлено 64 Гб.
Excel, надеюсь тоже 64бит? Повидимому, что group by, что union требуют создания индексов. Вот и режет движок Access строки. В SQL Server, например, ограничение на размер индекса в 900 байт. Так что ,Игорь, приходилось sha512 использовать. Пока на проме ошибок не было.
Изменено: Андрей VG - 28.11.2017 19:54:43
 
Я с хэшем только раз дело имел в одном проекте, там не особо критична была уникальность, обходился MD5. У меня даже и кодов других нет...
Нет кстати к слову готового проверенного кода sha512 на VBA  в копилку? :)
P.S. Сам нашёл - правда строка
Hello World
распухает в
LHT9F+2v2A6ER7DUZ0HuJDt+t03SFJoKsbkkb7MDgvJ+hT2FhXGeDmfL2g2q­j1FnEGRhXWRa4nrLFb+xRH9Fmw==
хотя ничего, любая строка смотрю на выходе даёт 88 символов... или массив в 64 элемента.

Код
Sub test()
Dim text As Object
Dim SHA512 As Object

Set text = CreateObject("System.Text.UTF8Encoding")
Set SHA512 = CreateObject("System.Security.Cryptography.SHA512Managed")

Debug.Print ToBase64String(SHA512.ComputeHash_2((text.GetBytes_4("Hello World"))))

End Sub

Function ToBase64String(rabyt)

  'Ref: http://stackoverflow.com/questions/1118947/converting-binary-file-to-base64-string
  With CreateObject("MSXML2.DOMDocument")
    .LoadXML "<root />"
    .DocumentElement.DataType = "bin.base64"
    .DocumentElement.nodeTypedValue = rabyt
    ToBase64String = Replace(.DocumentElement.text, vbLf, "")
  End With
End Function
Изменено: Hugo - 28.11.2017 20:36:54
 
AB1, а можно глянуть на структуру .CSV входящей и исходящей для образца?
Я б сгенерил массив входящий в нужный CSV, и результат кусками сливать можно, а то все в памяти висит и время не на обработку на генерацию жалко...
А то 144/2000000=24сек.(MSO2013x32)/=20сек.(MSO2016x64). А у меня памяти всего 4Гб.
Хотел 300/3000000, а он послал меня на ... out of memory
Изменено: AAF - 28.11.2017 20:40:02
 
В CSV-файле один столбец, данные по структуре близки тем, которые я привел в примере - http://rgho.st/7TcfgXYhP (600 000 строк в Excel-листе).
 
Цитата
Hugo написал:
любая строка смотрю на выходе даёт 88 символов... или массив в 64 элемента
Игорь, так sha512 - это 512 бит или 64 элемента байтового масса, а base64 - это уже отдельное преобразование в текст, в котором разрешены только 64 символа. База короче, поэтому текст длиннее.
 
Так и ладно - если вываливать массив в строку с разделителями - это ещё больше в любом случае будет.
А если напрягает потеря времени на отдельной функции - можно преобразование интегрировать в макрос.
 
Всем - привет!
VBA вполне годится для такой задачи. Все дело в алгоритме.
Код, приведенный ниже, из данных листа быстро создаст в папке ThisWorkbook.Path & "\OutFiles" текстовые файлы, в каждом из которых будут  уникальные строки одинаковой длины.
Кодом нужно обработать поочередно все  исходные данные, а затем данные из созданных  текстовых файлов (предварительно переместив эти файлы в другую папку). Результирующие текстовые файлы уникальных данных при желании можно объединить в один файл, но это уже несложно.
Затраты времени можно увидеть в окне Immediate при Const IsLog As Boolean = True

Код
Option Explicit
Option Compare Text

Sub CreateUniqDataFiles()
' ZVI:2017-11-28 http://www.planetaexcel.ru/forum/index.php?PAGE_NAME=read&TID=98608
  
  Const IsLog As Boolean = True
  
  Dim a(), b(), v
  Dim FF As Integer
  Dim i As Long, j As Long
  Dim Rng As Range
  Dim s As String, f As String, p As String
  Dim t As Single, tt As Single
  
  Debug.Print "== Start " & Now
  tt = Timer
  p = ThisWorkbook.Path & "\OutFiles"
  Set Rng = ThisWorkbook.Sheets(1).UsedRange.Resize(, 2)
  With Rng
    ' Calc lengths
    t = Timer
    With .Columns(2)
      .Formula = "=LEN(A1)"
      .Value = .Value
      ReDim b(WorksheetFunction.Min(.Cells) To WorksheetFunction.Max(.Cells))
      .ClearContents
    End With
    If IsLog Then Debug.Print "Length", Round(Timer - t, 3), "Total = " & Round(Timer - tt, 3)
    ' Sort
    t = Timer
    Rng.Sort .Cells(2), xlAscending, .Cells(1), , xlAscending, Header:=xlNo
    If IsLog Then Debug.Print "Sort", Round(Timer - t, 3), "Total = " & Round(Timer - tt, 3)
  End With
    
  ' Put values into a()
  t = Timer
  a() = Rng.Columns(1).Value
  If IsLog Then Debug.Print "a()", Round(Timer - t, 3), "Total = " & Round(Timer - tt, 3)
    
  ' Main
  t = Timer
  For i = 1 To UBound(a)
    j = Len(a(i, 1))
    If j > 0 And a(i, 1) <> s Then
      s = a(i, 1)
      If Not IsObject(b(j)) Then Set b(j) = New Collection
      b(j).Add s
    End If
  Next
  If IsLog Then Debug.Print "Main", Round(Timer - t, 3), "Total = " & Round(Timer - tt, 3)
  
  ' Create/Append files
  t = Timer
  If Dir(p, vbDirectory) = "" Then MkDir p
  For i = LBound(b) To UBound(b)
    If IsObject(b(i)) Then
      ' Copy content of the Collection to the s
      j = 0
      ReDim a(1 To b(i).Count + 1)
      For Each v In b(i)
        j = j + 1
        a(j) = v
      Next
      Set b(i) = Nothing
      s = Join(a, vbCrLf)
      ' Append data to the end of file
      f = p & "\" & Format(i, "0000") & ".txt"
      FF = FreeFile
      Open f For Binary Access Write As FF
      Seek FF, LOF(FF) + 1
      Put FF, , s
      Close FF
    End If
  Next
  If IsLog Then Debug.Print "Files", Round(Timer - t, 3), "Total = " & Round(Timer - tt, 3)
  
End Sub
Изменено: ZVI - 29.11.2017 11:56:30
 
Могу попробовать написать библу которая будет из .CSV делать .CSV с удалением дубликатов. Для этого нужно знать:1.
Цитата
bedvit написал:
сортировать перед выгрузкой
2.Разделитель текста 3.Кодировка.
А лучше файл пример (входящий, исходящий-если он отличается разделителями и кодировкой).
«Бритва Оккама» или «Принцип Калашникова»?
 
1. Сортировать не нужно.
2. Разделитель текста - двойные кавычки:
Код
"text string"

3. ANSI.
4. Первая строка содержит заголовок.

Примеры CSV

Изменено: AB1 - 29.11.2017 12:58:28
 
Если не вводить заголовки, у вас же исходно их не было, то можно таким вариантом на Power shell сделать.
Код
$(foreach ($line in Get-Content base?.csv){$line}) | sort | Get-Unique | Set-Content new.csv

Скорость несколько похуже - два тестовых файла по 500000 строк сшивались 4,5 минуты.
 
Пока получилось следующее:
Код
Public Sub UniquesADO()
    Const conStr = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=C:\Files\DemoUnion\CSV\;" & _
    "Extended Properties='text;HDR=Yes;FMT=Delimited';"
    
    Dim sSQL As String, lSQL As String
    Dim vStart As Single
    Dim Base() As Variant
    Dim i As Long
    Dim pConn As New ADODB.Connection
    Dim Conn As New ADODB.Connection
    Dim mrs As New ADODB.Recordset
    
    vStart = Timer
    
    lSQL = "Select [fname] From [base1.csv] WHERE LEN(fname)>255"
    
    sSQL = "Insert Into [result.csv] ([fname])"
    sSQL = sSQL & " Select [fname] From ("
    sSQL = sSQL & " Select [fname] From [base1.csv] WHERE LEN(fname)<256 GROUP BY [fname]) timport"
    
    pConn.Open conStr
    pConn.Execute sSQL, 128
    pConn.Close
    
    Conn.Open conStr
    mrs.Open lSQL, Conn
    
    On Error Resume Next

    i = 0
    
    ReDim Base(0 To 0)
    
    Do While Not mrs.EOF
    If Base(i) = Empty Then
    Base(i) = mrs.Fields(0).Value
    
    Else
    
    If mrs.Fields(0).Value <> Base(i) Then
    i = i + 1
    ReDim Preserve Base(0 To i)
    Base(i) = mrs.Fields(0).Value
    End If
    End If
    
    mrs.MoveNext
    Loop
    
    mrs.Close
    Conn.Close
    
    CollectionUniq Base
    
    Filename = "C:\Files\DemoUnion\CSV\result.csv"
    
    Open Filename For Append As #1
    For i = 0 To UBound(Base)
    Write #1, Base(i)
    Next i
    
    Close #1
    
    Debug.Print Timer - vStart
    
    End Sub

Код
Public Sub CollectionUniq(ByRef StringArray() As Variant)
  Dim x, y, Arr, i As Long, t As Single
  
  ReDim Arr(LBound(StringArray) To UBound(StringArray))
  Arr = StringArray
  If IsArray(Arr) Then
    ReDim y(0 To UBound(Arr))
    With New Collection
      On Error Resume Next
      For Each x In Arr
        If Len(x) > 0 Then
          Err.Clear
          .Add 0, CStr(x)
          If Err = 0 Then
            y(i) = x
            i = i + 1
          End If
        End If
      Next
    End With
  End If
  
  If y(i) = Empty Then
  ReDim Preserve y(0 To i - 1)
  End If
StringArray = y
End Sub

Информация считывается в 2 этапа - один для строк < 256, второй - для строк > 256.
Строки менее 256 символов считываются ADO, дубликаты удаляются тоже ADO.
Строки более 255 символов считываются ADO, дубликаты удаляются в коллекции.
С хешами пока не экспериментировал.
Изменено: AB1 - 29.11.2017 13:19:16
 
ZVI, благодарю за макрос.
Андрей VG, спасибо за вариант с Power shell, попробую.
 
Цитата
AB1 написал: благодарю за макрос.
Код из сообщения #54 быстрее словарей и коллекций, коллекции там использованы вместо массивов для упрощения кода. Тестовый файл с 600 000 строками, скачанный по ссылке из сообщения #51, на слабом компьютере обрабатывался за 20...30 секунд с формированием 169 текстовых файлов с уникальными данными.
Изменено: ZVI - 29.11.2017 13:34:25
Страницы: Пред. 1 2 3 4 След.
Наверх