I am having issues to filter dates in a ListObject, as some of them get well sorted and others don't at all.
What I want exactly is to filter dates, take the one that is the closest to today and put it in an other ListObject (basically, the tool I am creating is a database where all important events are stored and I want to send the most recent in a ListObject). For the moment, in order to try things, I just put the filtered date in the column to the right.
Here is the a quick screenshot to explain :
So what I am doing is that I get the first column data. If I get the same reference multiples times, it means I have multiple events and I am trying to sort it using this code :
Sub derniereDate()
Dim i As Long
Dim j As Long
Dim lastRow As Long
Dim lastRowS5 As Long
Dim lastDate As String
lastRow = Sheets(2).Cells(Rows.Count, "A").End(xlUp).Row
lastRowS5 = Sheets(5).Cells(Rows.Count, "A").End(xlUp).Row
j = 1
For i = 5 To lastRowS5 Step 1
lastDate = Format(Sheets(5).Range("M" & i), "MM/DD/YYYY")
While Sheets(5).Range("A" & i) = Sheets(5).Range("A" & i + j)
If lastDate < Sheets(5).Range("M" & i + j).Value Then
lastDate = Sheets(5).Range("M" & i + j)
End If
j = j + 1
Wend
If j <> 1 Then
Sheets(5).Range("P" & i) = lastDate
End If
i = i + (j - 1)
j = 1
Next i
End Sub
Here is a screenshot of a case where the sort doesn't work properly :
Excuse me for my English, thanks for help and staying up for more details if needed.
Sub derniereDate()
Dim i As Long
Dim j As Long
Dim lastRow As Long
Dim lastRowS5 As Long
Dim lastDate As Date
lastRow = Sheets(2).Cells(Rows.Count, "A").End(xlUp).Row
lastRowS5 = Sheets(5).Cells(Rows.Count, "A").End(xlUp).Row
j = 1
For i = 5 To lastRowS5 Step 1
lastDate = Format(Sheets(5).Range("M" & i), "MM/DD/YYYY")
While Sheets(5).Range("A" & i) = Sheets(5).Range("A" & i + j)
If lastDate < Sheets(5).Range("M" & i + j).Value Then
lastDate = Sheets(5).Range("M" & i + j)
End If
j = j + 1
Wend
If j <> 1 Then
Sheets(5).Range("P" & i) = lastDate
End If
i = i + (j - 1)
j = 1
Next i
End Sub
Simply had to change lastDate type... Sorry for the useless post...
Related
I am using a Macro to identify same details entered (in Column B, C and D) for multiple students (Column A).
This macro is working fine on approx 10,000 rows. But when I use it on full database ex: 1,00,000 rows it just got hanged.
Any help to in speeding up this macro will be very helpful.
`
Option Explicit
Sub test()
Dim lRow As Long, i As Long, j As Long
Dim c As Integer
Dim students() As Variant
Dim results() As Variant
lRow = Cells(Rows.Count, 1).End(xlUp).Row
ReDim results(lRow - 1)
students = Range("A1:D" & lRow).Value
For i = 2 To lRow
found = False
For j = 2 To lRow
If students(i, 1) = students(j, 1) Then GoTo skipStudent
For c = 1 To 4
If students(j, c) = "-" Or students(i, c) = "-" Then GoTo skipColumn
If students(i, c) = students(j, c) Then
results(i - 1) = results(i - 1) & "Same " & students(1, c) & " information with " & students(j, 1) & vbCrLf
End If
skipColumn:
Next
skipStudent:
Next
Next
Application.ScreenUpdating = False
For i = 2 To lRow
Cells(i, 5).Value = results(i - 1)
Next
Application.ScreenUpdating = True
End Sub
`
I try to find a vba solution for the following problem:
I have two columns and try to group column1 in a comma separate way to have less rows.
e.g.
example:
I tried this, and it worked - but It take too long (about 300.000 Rows). Is there any better solution that task?
*Its just one part of my macro
For Each r In fr
If st = "" Then
st = Application.WorksheetFunction.Clean(Trim(ws.Cells(r.row, "L").Value))
Else
If Not IsInArray(Split(st, ","), ws.Cells(r.row, "L").Value) Then
st = st & ", " & Application.WorksheetFunction.Clean(Trim(ws.Cells(r.row, "L").Value))
End If
End If
If usrCheck = True Then
If str = "" Then
str = Application.WorksheetFunction.Clean(Trim(ws.Cells(r.row, "A").Value))
Else
If Not IsInArray(Split(str, ","), ws.Cells(r.row, "A").Value) Then
str = str & ", " & Application.WorksheetFunction.Clean(Trim(ws.Cells(r.row, "A").Value))
End If
End If
End If
Next
Maybe using Dictionary would be fast. What about:
Sub Test()
Dim x As Long, lr As Long, arr As Variant
Dim dict1 As Object: Set dict1 = CreateObject("Scripting.Dictionary")
Dim dict2 As Object: Set dict2 = CreateObject("Scripting.Dictionary")
With Sheet1 'Change accordingly
'Return your last row from column A
lr = .Cells(.Rows.Count, 1).End(xlUp).Row
'Get array and loop through it
arr = .Range("A2:B" & lr).Value
For x = LBound(arr) To UBound(arr)
dict1(arr(x, 2)) = arr(x, 2)
Next
'Loop through dictionary filling a second one
For Each Key In dict1.keys
For x = LBound(arr) To UBound(arr)
If arr(x, 2) = Key Then dict2(arr(x, 1)) = arr(x, 1)
Next x
.Range("F" & .Cells(.Rows.Count, 6).End(xlUp).Row + 1) = Key
.Range("G" & .Cells(.Rows.Count, 7).End(xlUp).Row + 1) = Join(dict2.Items, ", ")
dict2.RemoveAll
Next
End With
End Sub
This will get you all unique items from column A though, so if there can be duplicates and you want to keep them, this is not for you =)
Try also this, please. It works only in memory and on my computer takes less then 3 seconds for 300000 rows. The range must be filtered, like in your picture. If not, the filtering can also be easily automated.
Private Sub CondensData()
Dim sh As Worksheet, arrInit As Variant, arrIn As Variant, i As Long
Dim arrFinal() As Variant, lastRow As Long, Nr As Long, El As Variant
Dim strTemp As String, k As Long
Set sh = ActiveSheet
lastRow = sh.Cells(sh.Rows.count, "A").End(xlUp).Row
arrIn = sh.Range("B2:B" & lastRow + 1).Value
'Determine the number of the same accurrences:
For Each El In arrIn
i = i + 1
If i >= 2 Then
If arrIn(i, 1) <> arrIn(i - 1, 1) Then Nr = Nr + 1
End If
Next
ReDim arrFinal(Nr, 1)
arrInit = sh.Range("A2:B" & lastRow).Value
For i = 2 To UBound(arrInit, 1)
If i = 1 Then
strTemp = arrInit(1, 1)
Else
If arrInit(i, 2) = arrInit(i - 1, 2) Then
If strTemp = "" Then
strTemp = arrInit(i, 1)
Else
strTemp = strTemp & ", " & arrInit(i, 1)
End If
Else
arrFinal(k, 0) = arrInit(i - 1, 2)
arrFinal(k, 1) = strTemp
k = k + 1: strTemp = ""
End If
End If
Next i
sh.Range("C2:D" & lastRow).Clear
sh.Range("C2:D" & k - 1).Value = arrFinal
sh.Range("C:D").EntireColumn.AutoFit
MsgBox "Solved..."
End Sub
It will return the result in columns C:D
'I am trying to sum the columns of specific headers in a particular row but I am getting total sum of all columns of that row irrespective of header. Can someone please tell me my mistake?Please see the attached image for sample input output.
Dim DSum As Integer
Dim PSum As Integer
With wsn
NIMsLastRow = Worksheets("NIMSCarrierCount").Cells(Rows.Count, 1).End(xlUp).Row
NIMsLastCol = Worksheets("NIMSCarrierCount").Cells(1, Columns.Count).End(xlToLeft).Column
For j = 2 To NIMsLastRow
DSum = 0
PSum = 0
For k = 2 To NIMsLastCol
If .Cells(1, k).Value = "LTE 1900Deployed" Or "LTE 2500Deployed" Or "LTE 800Deployed" Or "UnassignedDeployed" Then
DSum = DSum + CInt(.Cells(j, k).Value)
End If
If .Cells(1, k).Value = "LTE 1900Planning" Or "LTE 2500Planning" Or "LTE 800Deployed" Or "UnassignedPlanning" Then
PSum = PSum + CInt(.Cells(j, k).Value)
End If
Next k
.Cells(j, NIMsLastCol + 1).Value = DSum
.Cells(j, NIMsLastCol + 2).Value = PSum
Next j
End With
I would consider a re-write to use Select Case which will also solve the error around your test conditions. Remember to use Option Explicit at the top of your module to check your variable declarations. And is it possible that you might need Double for your DSum and PSum? Note I have exchanged Integers for Longs to avoid potential overflow (happens with large numbers when trying to store something too big for the declared datatype)
Option Explicit 'Always use Option Explicit
Sub test()
Dim wsn As Worksheet
Set wsn = ThisWorkbook.Worksheets("NIMSCarrierCount") 'assumption this is correct sheet assigment
Dim DSum As Long 'use Long to avoid potential overflow
Dim PSum As Long
Dim NIMsLastRow As Long 'declare all variables
Dim NIMsLastCol As Long
Dim j As Long
Dim k As Long
With wsn
NIMsLastRow = .Cells(.Rows.Count, 1).End(xlUp).Row
NIMsLastCol = .Cells(1, .Columns.Count).End(xlToLeft).Column
For j = 2 To NIMsLastRow
DSum = 0
PSum = 0
Dim testValue As String
For k = 2 To NIMsLastCol
testValue = .Cells(1, k)
Select Case testValue
Case "LTE 1900Deployed", "LTE 2500Deployed", "UnassignedDeployed"
DSum = DSum + CLng(.Cells(j, k))
Case "LTE 1900Planning", "LTE 2500Planning", "UnassignedPlanning"
PSum = PSum + CLng(.Cells(j, k))
Case "LTE 800Deployed"
DSum = DSum + CLng(.Cells(j, k))
PSum = PSum + CLng(.Cells(j, k))
End Select
Next k
.Cells(j, NIMsLastCol + 1).Value = DSum
.Cells(j, NIMsLastCol + 2).Value = PSum
Next j
End With
End Sub
Your if statement has been written incorrectly.
The Or "LTE 2500Deployed" is being evaluated to True for every query.
You need to specify fully for each parameter as such
.Cells(1, k).Value = "LTE 1900Deployed" Or .Cells(1, k).Value = "LTE 2500Deployed" Or...
I have product codes: (they are in C column of active sheet)
DO-001
DO-002
DO-003
DO-004
And I have big list of data: (they are in C column of "Sheet1")
41300100_DO-001_14215171
41300104_DO-001_14215173
K1_ISK_41300661_DO-002_13190369
NP_41533258_DO-003_14910884
DO-003_DD_44_ddd
And I want to count how many times do the product codes appear in the list of data. So the result for this case'd be: (result is H column of active sheet)
DO-001 2
DO-002 1
DO-003 2
DO-004
I have done this with this code:
Sub CountcodesPLC()
Dim i, j As Integer, icount As Integer
Dim ldata, lcodes As Long
icount = 0
lcodes = Cells(Rows.Count, 3).End(xlUp).Row
ldata = Worksheets("Sheet1").Cells(Rows.Count, 3).End(xlUp).Row
For i = 10 To lcodes
For j = 2 To ldata
If InStr(Worksheets("Sheet1").Range("C" & j), Range("C" & i)) <> 0 Then
icount = icount + 1
End If
Next j
If icount <> 0 Then
Range("H" & i).Value = icount
End If
icount = 0
Next i
End Sub
But I want to change it, so if the list of data contains some key words like "NP", "ISK", then not to count them, or if the first part of the data is the code then also not to count them, so the result for this example would be:
DO-001 2
DO-002
DO-003
DO-004
Also, I'll have around 1.000 product codes, and around 60.000 strings of data.
Will my code crash?
Seems your code is OK. But if you want to match only the first part of string (a'ka StartsWith), i'd change only this line:
If InStr(Worksheets("Sheet1").Range("C" & j), Range("C" & i)) <> 0 Then
to:
If Worksheets("Sheet1").Range("C" & j) Like Range("C" & i) & "*" Then
For further details, please see: Wildcard Characters used in String Comparisons
Use Dictionnary
Dim Dict As Scripting.Dictionary
Set Dict = New Scripting.Dictionary
Arr = Split("refer your text here", "_")
For I = LBound(Arr) To UBound(Arr)
If Dict.Exists(Arr(I)) Then
Dict(Arr(I)) = Dict(Arr(I)) + 1 'increment
Else
Dict.Add Arr(I), 1
End If
Next I
This may be OTT for the requirement but should work quite quickly.
Public Sub Sample()
Dim WkSht As Worksheet
Dim LngRow As Long
Dim AryLookup() As String
Dim VntItem As Variant
'We put what we want to search into an array, this makes it a lot quicker to search
Set WkSht = ThisWorkbook.Worksheets("Sheet1")
ReDim AryLookup(0)
LngRow = 1
Do Until WkSht.Range("A" & LngRow) = ""
If AryLookup(UBound(AryLookup, 1)) <> "" Then ReDim Preserve AryLookup(UBound(AryLookup, 1) + 1)
AryLookup(UBound(AryLookup, 1)) = Trim(UCase(WkSht.Range("A" & LngRow)))
LngRow = LngRow + 1
Loop
Set WkSht = Nothing
'Then we go down the list and check the array against each item
Set WkSht = ActiveSheet
LngRow = 1
Do Until WkSht.Range("A" & LngRow) = ""
WkSht.Range("B" & LngRow) = 0
For Each VntItem In AryLookup()
'This looks for the match without any of the exclusion items
If (InStr(1, VntItem, Trim(UCase(WkSht.Range("A" & LngRow)))) <> 0) And _
(InStr(1, VntItem, "NP") = 0) And _
(InStr(1, VntItem, "ISK") = 0) Then
WkSht.Range("B" & LngRow) = WkSht.Range("B" & LngRow) + 1
End If
Next
LngRow = LngRow + 1
Loop
Set WkSht = Nothing
MsgBox "Done"
End Sub
Basically, the 60,000 data strings will go into an array in memory, then the array will be searched against the 1,000 products. Searching in memory should be quick.
One thing I would raise is the exclusion method may produce false positives.
For example, excluding NP will exclude: -
NP_41533258_DO-003_14910884
NPA_41533258_DO-003_14910884
41533258_ANP_DO-003_14910884
You may want to think about the method overall.
Have you considered an array formula, not sure how it will perform vs code, but, you could do something along these lines, where list is in A and prod numbers in B
=SUM(IF(NOT(ISERR(SEARCH(B1 & "_",$A$1:$A$5,1)))*(ISERR(SEARCH("NP_",$A$1:$A$5,1))),1,0))
Where "NP" would be replaced by a range containing the exclusions, I've left as NP to show what's happening.
The code would be like this. But I don't know the speed.
Sub test()
Dim vDB, vLook, vSum(), Sum As Long
Dim Ws As Worksheet, dbWs As Worksheet
Dim s As String, sF As String, sCode As String
Dim i As Long, j As Long, n As Long
Set dbWs = Sheets("Sheet1")
Set Ws = ActiveSheet
With Ws
vLook = .Range("a1", .Range("a" & Rows.Count).End(xlUp))
End With
With dbWs
vDB = .Range("c1", .Range("c" & Rows.Count).End(xlUp))
End With
n = UBound(vLook, 1)
ReDim vSum(1 To n, 1 To 1)
For i = 1 To n
sF = Split(vLook(i, 1), "-")(0)
sCode = Replace(vLook(i, 1), sF, "")
Sum = 0
For j = 1 To UBound(vDB, 1)
s = vDB(j, 1)
If Left(s, Len(sF)) = sF Or InStr(s, "NP") Or InStr(s, "ISK") Then
Else
If InStr(s, sCode) Then
Sum = Sum + 1
End If
End If
Next j
If Sum > 0 Then
vSum(i, 1) = Sum
End If
Next i
Ws.Range("h1").Resize(n) = vSum
End Sub
I need to a dynamic way to concatinate some cells in a row with a delimiter (in this instance |) as the columns move about (per project) this has to be by header names (there might be from 2 to many) columns that need to be concatinated for a project
I am trying to use arrays as there can be as many as 4000,000 rows
I have been trying for hours and here is my effort I know it is very wrong but I am at a loss
Thank you
Sub CAT()
fCAT "ElementsFile", "ElementsFile", "D", Array("Age", "Gender Identity", "Ethnicity1", "Ethnicity1")
End Sub
Sub fCAT(sShtName As String, pbShtName As String, InsertCol As String, ar As Variant)
Dim myresult
Dim col1 As String, col2 As String, col3 As String, col4 As String
Dim aLR As Long, i As Long, j As Long, k As Long
'Totaly at a loss here
For i = LBound(ar) To UBound(ar)
Dim ari As Variant
Dim coli As String
Next i
Set wsS = ThisWorkbook.Sheets(sShtName)
Set wsPB = ThisWorkbook.Sheets(pbShtName)
With wsS
aLR = .Range("A" & .Rows.Count).End(xlUp).Row
For i = LBound(ar) To UBound(ar)
j = .Rows(1).Find(ar(i)).Column
ari = .Range(Cells(1, j), Cells(aLR, j)).Select
Next i
End With
'Totaly at a loss here
ReDim myresult(1 To aLR, 1 To aLR)
For k = 1 To aLR
For i = LBound(ar) To UBound(ar)
j = wsS.Rows(1).Find(ar(i)).Column
myresult(k, 1) = Cells(k, j) & "|" & Cells(k, j + 1) & "|" & Cells(k, j + 2) & "|" & Cells(k, j + 3)
Next i
Next k
wsT.Range("D1").Resize(aLR, 1) = myresult
End Sub
Here is what I finally came up with a bit of a mess maybe but it works
Sub concat()
Dim myresult, CN
Dim HN As Variant
Dim wsS As Worksheet, wsPB As Worksheet
Dim str As String
Dim LR As Long, i As Long, j As Long, k As Long
HN = Array("Age", "Gender Identity", "Ethnicity1", "Ethnicity2")
Set wsS = ThisWorkbook.Sheets("ElementsFile")
Set wsPB = ThisWorkbook.Sheets("ElementsFile")
wsPB.Columns(4).Insert
ReDim CN(0 To UBound(HN))
With wsS
LR = .Range("A" & .Rows.Count).End(xlUp).Row
'Get Array of column numbers coresponding to Header names
For i = 0 To UBound(HN)
j = wsS.Rows(1).Find(HN(i)).Column
CN(i) = j
Next i
End With
ReDim myresult(1 To LR, 1 To 1)
For i = 1 To LR
str = vbNullString
If Not (IsEmpty(Cells(i, CN(0))) And IsEmpty(Cells(i, CN(1)))) Then
For k = UBound(HN) To 0 Step -1
If k <> UBound(HN) Then
str = Cells(i, CN(k)) & "|" & str
Else: str = Cells(i, CN(k)) & str
End If
Next k
myresult(i, 1) = str
Else
myresult(i, 1) = vbNullString
End If
Next i
str = vbNullString
wsPB.Range("D1").Resize(LR, 1) = myresult
End Sub