02. maj 2003 - 13:36Der er
44 kommentarer og 3 løsninger
Sammenlignings makro (meget langsom)
Hola exp´er
kabbak har skrevet denne makro til mig:
------------------------------------------------- Sub Find_Ikke_Ens_I_Ark() Dim F, C, T, U, A As Integer, Q As Boolean Application.ScreenUpdating = False A = 1
Worksheets("Nyliste").Activate F = ActiveCell.SpecialCells(xlLastCell).Row ' Finder ud af hvor mange rækker der er med data på ark1
Worksheets("Fastliste").Activate U = ActiveCell.SpecialCells(xlLastCell).Row ' Finder ud af hvor mange rækker der er med data på ark2
For T = 1 To F Q = True For C = 1 To U Worksheets("Nyliste").Activate If Worksheets("NyListe").Cells(T, 2) = Worksheets("Fastliste").Cells(C, 2) Then Q = False GoTo Skift End If
Next C
Skift: If Q = True Then Sheets("Nyliste").Select Rows(T & ":" & T).Select Selection.Copy Sheets("ResultatListe").Select Rows(A & ":" & A).Select ActiveSheet.Paste A = A + 1 Q = False Application.CutCopyMode = False End If Next T Sheets("ResultatListe").Select Application.ScreenUpdating = True Application.CutCopyMode = False Range("A1").Select End Sub ------------------------------------
Som sammenligner to lister og laver en ny liste med de poster der ikke på begge liste !
Men mine lister er på over 20.000 rækker ... så den er meget langsom, hvis den ikke dumper :o(
En der har et forslag til hvordan det kan gøres hurtigere og sikre
Brug af AI afslører de svagheder, virksomheder allerede har opbygget gennem års cloud-transformation, nye SaaS-løsninger og fragmenterede sikkerhedssystemer.
Ja ... det kan jeg godt se ... men det er ikke tilfredstillende at den crasher, Hvis man nu kunne lave den bare lidt hurtigere vil den nok også blive mere stabil
Var det ikke en idé, at placere dine data i Access og lave en SQL forespørgsel, som sammenlignede dine kolonner. Jeg mener, at det er en Outerjoin der skal anvendes. Du kan stadig gøre det fra Excel, ved at koble dig på databasen i din VBA kode.
Men jeg har et også et eksempel, som kan udføre sammenligningen på 20000 rækker. Eksemplet tester kun på den ene række og ikke omvendt, men det kan jo laves :-) Det tager ca. 1 min på min maskine at sammenligne. Eksemplet ser således ud:
Function Sammenlign(ByVal refmyrange As Range, ByVal Myrange As Range) As Boolean On Error GoTo errhandler
If Not IsError(Application.WorksheetFunction.Match(refmyrange, Myrange, 0)) Then Sammenlign = True Exit Function errhandler: Sammenlign = False End Function
Sub Test() Set Myrange = Worksheets("Ark1").Range(Cells(1, 2), Cells(20000, 2)) a = 1 For i = 1 To 20000 Set refmyrange = Worksheets("Ark1").Cells(i, 1)
If Not Sammenlign(refmyrange, Myrange) Then Worksheets("Ark1").Cells(a, 3).Value = Worksheets("Ark1").Cells(i, 1) a = a + 1 End If Next End Sub
chewie Nu kan jeg se du allerede har lavet een del, og ved ikke om du har set nedenstående før. Jeg ved heller ikke om de er hurtigere (som blackadder siger, så er det grumme mange sammenligninger) men det er da værd at prøve.
Ja - koden skal placeres i et modul. I eksemplet er det Ark1 der refereres til. Den ene kolonne med data er placeret i området a1:a20000 Den anden kolonne er placeret i området b1:b20000.
Hvis du ikke kan få det til at virke, kan jeg sende regnearket til dig via mail :-)
Synes godt om
Slettet bruger
02. maj 2003 - 18:49#12
Prøv denne her: --------------- Sub FindUnique()
Dim ny, fast, resultat As Worksheet Dim nyRowCount, fastRowCount, resultatRowCount, i, j, k As Integer Dim nyCol, fastCol As Variant Dim duplicate As Boolean
Set ny = Worksheets("NyListe") Set fast = Worksheets("FastListe") Set resultat = Worksheets("ResultatListe")
breakpoint: For i = k To UBound(nyCol, 1) duplicate = False Application.StatusBar = "Sammenligner række: " & i For j = 1 To UBound(fastCol, 1) If nyCol(i, 1) = fastCol(j, 1) Then duplicate = True k = i + 1 GoTo breakpoint End If Next j If duplicate = False Then Worksheets("ResultatListe").Cells(resultatRowCount, 1) = nyCol(i, 1) resultatRowCount = resultatRowCount + 1 End If Next i
Application.StatusBar = False
End Sub
-----------------------
Den bruger "bak-metoden", med et variant-array der indlæses i hukommelsen. Den tager ca. 5 min. på min egen maskine.
Denne makro tager 14 sek. om 2*20000 celler med 4000 rækker der skal overføres til resultatlisten (på en gammel P350 mhz og 128Ram) Inden makroen køres skal du under Tools / References sætte flueben i "MicroSoft Scripting Runtime" Den er sat til at chekke kolonne B og overføre cellerne fra kolonne A-F.
Option Explicit Option Base 1 '''Skriver alle de værdi, der findes i TB2 og IKKE i TB1, til TB3 Sub Compare2() '''Dim af variable Const SearchCol As Long = 1 Const MaxCols As Long = 6
Dim TB1 As Worksheet, TB2 As Worksheet, TB3 As Worksheet Dim xcol As Scripting.Dictionary Dim aForskel Dim starttid As Double Dim fundet As Boolean, Last1 As Long, Last2 As Long Dim i As Long, z As Long, x As Long
'''Initialisering af variabler starttid = Timer Set xcol = New Scripting.Dictionary Set TB1 = ActiveWorkbook.Worksheets("NyListe") Set TB2 = ActiveWorkbook.Worksheets("FastListe") Set TB3 = ActiveWorkbook.Worksheets("ResultatListe")
'''Hent alle værdi fra TB1 ind i Collection xcol On Error Resume Next For i = 1 To Last1 xcol.Add Item:=CStr(TB1.Cells(i, SearchCol)), Key:=CStr(TB1.Cells(i, SearchCol)) Next
'''Check alle celler i TB2 (kol A) om disse findes i xcol '''Hvis de ikke gør så placer dem i varianten aForskel On Error Resume Next
For i = 1 To Last2 If xcol.Exists(CStr(TB2.Cells(i, SearchCol))) Then fundet = True Else fundet = False If fundet = False Then z = z + 1 For x = 1 To MaxCols aForskel(z, x) = TB2.Cells(i, x) Next End If fundet = True
Next Set xcol = Nothing Application.StatusBar = "Beregning færdig, fylder nu celler" '''Overfør aForskel til TB3 TB3.Range(Cells(1, 1), Cells(UBound(aForskel, 1), MaxCols)) = aForskel MsgBox "færdig tid : " & Timer - starttid Set xcol = Nothing Set aForskel = Nothing Application.StatusBar = False End Sub
Måske har jeg rodet det lidt rundt :-) Hvis en linie fra FastListe ikke findes i NyListe skriver den linien fra fastliste. Det er nu ikke et stort problem at ændre, jeg skal bare lige vide hvad der ønskes på resultatarket. Jeg blev nok lidt forvirret. De skriver godt nok fint her. Men du må da indrømme at den er hurtig....... :-)
ok, chewie. Den burde virke med den lille rettelse, men jeg har nu prøvet at lave en mere generel makro til dette formål. Jeg er ikke helt færdig men du kan da få en "beta"-version, så kan vi jo se om der nogensinde kommer en endelig version :-) Denne makro Chekker begge veje og laver 2 resultater ved siden af hinanden. Ca. 35 sek. for 20000 * 2 rækker. Sub Init_Compare sørger bare for opsætning til Compare2Lists, som er motoren. Du skal bare udpege overskrifter for hvert område, når du bliver spurgt og derefter første celle i den kolonne der skal bruges til sammenligning. De kolonner der bliver markeret under udvælgelse af overskrifter er også dem der "flyttes" med om i det udpegede resultatark. Test og vend tilbage.
Option Explicit Option Base 1 Sub Init_Compare() '''Dim af variable Dim TB1 As Range, TB2 As Range, TB3 As Range Dim Temp As Range Dim IndexCol1 As Long, IndexCol2 As Long Dim StartTid As Double Dim ReturnArray As Variant
With Application Set TB1 = .InputBox("Marker overskrift af område 1", Type:=8) TB1.Parent.Activate Set Temp = .InputBox("Marker 1.celle i sammenligningskolonnen", Type:=8) IndexCol1 = Temp.Column - TB1.Column + 1 Set TB2 = .InputBox("Marker overskrift af område 2", Type:=8) TB2.Parent.Activate Set Temp = .InputBox("Marker 1.celle i sammenligningskolonnen", Type:=8) IndexCol2 = Temp.Column - TB2.Column + 1 Set TB3 = .InputBox("Marker 1. celle af resultatområde", Type:=8) TB3.Parent.Activate End With
MsgBox "Færdig tid : " & Timer - StartTid Set ReturnArray = Nothing End Sub
Sub DoCompare2Lists(WS1 As Range, WS2 As Range, SearchCol1 As Long, SearchCol2 As Long, aForskel As Variant) Dim xCol As Scripting.Dictionary Dim Fundet As Boolean, Last1 As Long, Last2 As Long Dim Cols2 As Long Dim i As Long, z As Long, x As Long
Set xCol = New Scripting.Dictionary Cols2 = WS2.Columns.Count Last1 = WS1.Cells(65536, SearchCol1).End(xlUp).Row Last2 = WS2.Cells(65536, SearchCol2).End(xlUp).Row ReDim aForskel(Last2, Cols2) z = 0
On Error Resume Next With WS1 For i = 1 To Last1 xCol.Add Item:=CStr(.Cells(i, SearchCol1)), Key:=CStr(.Cells(i, SearchCol1)) Next End With With WS2 For i = 1 To Last2 Fundet = xCol.Exists(CStr(.Cells(i, SearchCol2))) If Not Fundet = True Then z = z + 1 For x = 1 To Cols2 aForskel(z, x) = .Cells(i, x) Next End If Fundet = True Next End With Set xCol = Nothing End Sub
Synes godt om
Slettet bruger
03. maj 2003 - 21:37#23
Jeg bøjer mig i støvet... :-) Den virker og er tilmed møg-hurtig.
Synes godt om
Slettet bruger
03. maj 2003 - 21:54#24
Den kan vistnok også klares med denne array formel:
Indsæt i ResultatListe og træk nedad =IF(COUNTIF(NyListe!B2:B20723;FastListe!A2)=0;B1;"")
Tak for det, gutter. Men helst ingen knæfald, jeg er ikke engang guru endnu :-) Dette var et lille eksperiment for mig med scripting.Dictionary. En dejlig lille avanceret ting, der ikke står så meget om i hjælpen.
hmm hmm .. hvis jeg åbner det ark jeg har lavet hjemme ... er Runtime afkrysset også virker det :o) .... men det er da stadig underligt at jeg ikke kan her på arbejdet :(
Måske ikke. Nogle firmaer vælger ikke at installere scripting runtime, som en ekstra virus-sikring. Check lige om I har valgt dette. Eller må vi jo lave det om, det er sikkert ikke umuligt, men kan blive lidt langsommere :-)
Du kan (for at teste) prøve at bruge dette modul. Sub Init_Compare()
'''Dim af variable Dim TB1 As Range, TB2 As Range, TB3 As Range, TB4 As Range Dim Temp As Range Dim IndexCol1 As Long, IndexCol2 As Long Dim StartTid As Double Dim ReturnArray As Variant
Set TB1 = Sheet1.Range("A1:F1") '1. inputområde Set TB2 = Sheet2.Range("A1:f1") '2. inputområde
Set TB3 = Sheet3.Range("A1") '1. outputområde Set TB4 = Sheet3.Range("G1") '2. outputområde IndexCol1 = 2 'anden kolonne i TB1 (B) IndexCol2 = 2 'anden kolonne i TB2 (B)
Du lavede denne super fede makro i 2003 og nu har jeg pludselig fået brug for den igen. dog med et lille tvist .. jeg skal nu bruge alle dem som er ens.
kan du hjælpe med at tviste den ?
--
Option Explicit Option Base 1 Sub Init_Compare() '''Dim af variable Dim TB1 As Range, TB2 As Range, TB3 As Range Dim Temp As Range Dim IndexCol1 As Long, IndexCol2 As Long Dim StartTid As Double Dim ReturnArray As Variant
With Application Set TB1 = .InputBox("Marker overskrift af område 1", Type:=8) TB1.Parent.Activate Set Temp = .InputBox("Marker 1.celle i sammenligningskolonnen", Type:=8) IndexCol1 = Temp.Column - TB1.Column + 1 Set TB2 = .InputBox("Marker overskrift af område 2", Type:=8) TB2.Parent.Activate Set Temp = .InputBox("Marker 1.celle i sammenligningskolonnen", Type:=8) IndexCol2 = Temp.Column - TB2.Column + 1 Set TB3 = .InputBox("Marker 1. celle af resultatområde", Type:=8) TB3.Parent.Activate End With
MsgBox "Færdig tid : " & Timer - StartTid Set ReturnArray = Nothing End Sub
Sub DoCompare2Lists(WS1 As Range, WS2 As Range, SearchCol1 As Long, SearchCol2 As Long, aForskel As Variant) Dim xCol As Scripting.Dictionary Dim Fundet As Boolean, Last1 As Long, Last2 As Long Dim Cols2 As Long Dim i As Long, z As Long, x As Long
Set xCol = New Scripting.Dictionary Cols2 = WS2.Columns.Count Last1 = WS1.Cells(65536, SearchCol1).End(xlUp).Row Last2 = WS2.Cells(65536, SearchCol2).End(xlUp).Row ReDim aForskel(Last2, Cols2) z = 0
On Error Resume Next With WS1 For i = 1 To Last1 xCol.Add Item:=CStr(.Cells(i, SearchCol1)), Key:=CStr(.Cells(i, SearchCol1)) Next End With With WS2 For i = 1 To Last2 Fundet = xCol.Exists(CStr(.Cells(i, SearchCol2))) If Not Fundet = True Then z = z + 1 For x = 1 To Cols2 aForskel(z, x) = .Cells(i, x) Next End If Fundet = True Next End With Set xCol = Nothing End Sub
Synes godt om
Ny brugerNybegynder
Din løsning...
Tilladte BB-code-tags: [b]fed[/b] [i]kursiv[/i] [u]understreget[/u] Web- og emailadresser omdannes automatisk til links. Der sættes "nofollow" på alle links.