I modified the code only at one point because it was what I needed but I need something extra and I can't figure out how to do it.
Here is the original code from this post :
Sub test()
Dim lastRow As Integer, i As Integer
Dim cel As Range, rng As Range, sortRng As Range
Dim curString As String, nextString As String
Dim haveHeaders As Boolean
haveHeaders = False ' Change this to TRUE if you have headers.
lastRow = Cells(1, 1).End(xlDown).Row
If haveHeaders Then 'If you have headers, we'll start the ranges in Row 2
Set rng = Range(Cells(2, 1), Cells(lastRow, 1))
Set sortRng = Range(Cells(2, 1), Cells(lastRow, 2))
Else
Set rng = Range(Cells(1, 1), Cells(lastRow, 1))
Set sortRng = Range(Cells(1, 1), Cells(lastRow, 2))
End If
' First, let's resort your data, to get all of the "Column A" values in order, which will group all duplicates together
With ActiveSheet
.Sort.SortFields.Clear
.Sort.SortFields.Add Key:=rng, SortOn:=xlSortOnValues, Order:=xlAscending, DataOption:=xlSortNormal
With .Sort
.SetRange sortRng
.Header = xlGuess
.MatchCase = False
.Orientation = xlTopToBottom
.SortMethod = xlPinYin
.Apply
End With
' Now, let's move all "Column B" data for duplicates into Col. C
' We can check to see if the cell's value is a duplicate by simply counting how many times it appears in `rng`
Dim isDuplicate As Integer, firstInstanceRow As Integer, lastInstanceRow As Integer
If haveHeaders Then
curString = Cells(2, 1).Value
Else
curString = Cells(1, 1).Value
End If
Dim dupRng As Range 'set the range for the duplicates
Dim k As Integer
k = 0
For i = 1 To lastRow
If i > lastRow Then Exit For
Cells(i, 1).Select
curString = Cells(i, 1).Value
nextString = Cells(i + 1, 1).Value
isDuplicate = WorksheetFunction.CountIf(rng, Cells(i, 1).Value)
If isDuplicate > 1 Then
firstInstanceRow = i
Do While Cells(i, 1).Offset(k, 0).Value = nextString
'Cells(i, 1).Offset(k, 0).Select
lastInstanceRow = Cells(i, 1).Offset(k, 0).Row
k = k + 1
Loop
Range(Cells(firstInstanceRow + 1, 2), Cells(lastInstanceRow, 3)).Copy
Cells(firstInstanceRow, 5).PasteSpecial xlPasteValues
Application.CutCopyMode = False
Range(Rows(firstInstanceRow + 1), Rows(lastInstanceRow)).EntireRow.Delete
k = 0
lastRow = Cells(1, 1).End(xlDown).Row
End If
Next i
End With
End Sub
What I did is:
changed this:
Range(Cells(firstInstanceRow + 1, 2), Cells(lastInstanceRow, 2)).Copy
Cells(firstInstanceRow, 3).PasteSpecial Paste:=xlPasteAll, Operation:=xlNone, SkipBlanks:=False, Transpose:=True
Application.CutCopyMode = False
to
Range(Cells(firstInstanceRow + 1, 2), Cells(lastInstanceRow, 3)).Copy
Cells(firstInstanceRow, 5).PasteSpecial xlPasteValues
Application.CutCopyMode = False
What I have is:
Column A has duplicates.
Column B has unique value.
And column C has the qty for the unique values.
It works until the copy and paste part with the exception that it copies either column C under value from column B or the other way is that it copies each value from Column B with the qty from Column C but when it finishes, it deletes all the duplicates.
Example
Column A Column B column C
322 sku322 qty 20
322 322sku qty 25
it outputs like
Column D column E
sku322 qty 20
322sku qty 25
And when it's finished, it delete the second row. This means that i don't have the second unique value.
Or it outputs like:
Column D Column E
sku322 322sku
qty 20 qty 25
And then it delete the last row and I don't have the qty anymore.
From my way of thinking if there is no way to paste on the same line, that would mean that after each find it should retake the loop and not copy/paste in bulk. But I tried multiple ways and can't seem to find a way to make it work.
Hows this? Screenshot of the results:
Note: If you want the ENTIRE 'unique-sku' column instead of just the country code, change
country = Right(Cells(i, 2), 2)
to
country = Cells(i, 2).Value
Code:
Sub Macro1()
'
' Macro1 Macro
'
Dim country As String, qty As Integer
Dim dict As Object: Set dict = CreateObject("Scripting.Dictionary")
' Headers
dict("country") = "sum"
' Loop through all rows starting on row 2; per Column A
For i = 2 To Sheets("Sheet1").Cells(1, 1).End(xlDown).Row
' Country = last 2 letters of Column B
country = Right(Cells(i, 2), 2)
qty = CInt(Cells(i, 3).Value)
' If it already exists, add the new amount to the sum.
If dict.Exists(country) Then
qty = dict(country) + qty
End If
' This will create it if it doesn't already exist. Otherwise, update.
dict(country) = qty
Next
' Here are some display options.
' Horizontal
Range("F2").Resize(1, UBound(dict.Keys()) + 1).Value = dict.Keys()
Range("F3").Resize(1, UBound(dict.Items()) + 1).Value = dict.Items()
' Vertical
Range("F5").Resize(UBound(dict.Keys()) + 1).Value = WorksheetFunction.Transpose(dict.Keys())
Range("G5").Resize(UBound(dict.Items()) + 1).Value = WorksheetFunction.Transpose(dict.Items())
Set dict = Nothing
'
End Sub
So i found a workaround, i don't know if it's the most feasable one but it works and for 10.000 rows it does it in 40 seconds to 1 minute max.
You need to create 3 modules and a function (i did not want to put the function in the on the modules.
Module 1
Sub Simplify()
Application.Run "Module9.RemovePart"
Application.Run "Module10.SameRowDuplicates"
End Sub
Module 2
Private Sub RemovePart()
Dim fndList As Variant
Dim fndRplc As Variant
With ActiveSheet
Range("B1").EntireColumn.Insert 'Here i inserted a new column so i can duplicate the first column
Range("A1", Range("A" & Rows.Count).End(xlUp)).Copy ' Copied the first column to the inserted one
Range("B1", Range("B" & Rows.Count).End(xlUp)).PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks:=False
Application.CutCopyMode = False
lastRow = Cells(Rows.Count, "A").End(xlUp).Row ' selected first column to remove the end of the sku
fndList = Array("FR", "DE", "ES") ' here you can just change to whatevery you want to remove
fndRplc = "" ' here is what it replaces it with
For x = LBound(fndList) To UBound(fndList)
For i = lastRow To 1 Step -1
Range("A1").EntireColumn.Replace What:=fndList(x), Replacement:=fndRplc, _
LookAt:=xlPart, SearchOrder:=xlByColumns, MatchCase:=False, _
SearchFormat:=False, ReplaceFormat:=False
Next i
Next x
End With
End Sub
Module 3
Private Sub SameRowDuplicates()
Dim lastRow As Integer, i As Integer
Dim cel As Range, Rng As Range, sortRng As Range
Dim curString As String, nextString As String
Dim haveHeaders As Boolean
haveHeaders = True ' Change this to TRUE if you have headers.
lastRow = Cells(1, 1).End(xlDown).Row
If haveHeaders Then 'If you have headers, we'll start the ranges in Row 2
Set Rng = Range(Cells(2, 1), Cells(lastRow, 1))
Set sortRng = Range("A2").CurrentRegion
Else
Set Rng = Range(Cells(1, 1), Cells(lastRow, 1))
Set sortRng = Range("A1").CurrentRegion
End If
' First, let's resort your data, to get all of the "Column A" values in order, which will group all duplicates together
With ActiveSheet
.Sort.SortFields.Clear
.Sort.SortFields.Add Key:=Rng, SortOn:=xlSortOnValues, Order:=xlAscending, DataOption:=xlSortNormal
With .Sort
.SetRange sortRng
.Header = xlYes
.MatchCase = False
.Orientation = xlTopToBottom
.SortMethod = xlPinYin
.Apply
End With
' Now, let's move all "Column B" data for duplicates into Col. C
' We can check to see if the cell's value is a duplicate by simply counting how many times it appears in `rng`
Dim isDuplicate As Integer, firstInstanceRow As Integer, lastInstanceRow As Integer
If haveHeaders Then
curString = Cells(2, 1).Value
Else
curString = Cells(1, 1).Value
End If
Dim dupRng As Range 'set the range for the duplicates
Dim k As Integer
k = 0
For i = 1 To lastRow
If i > lastRow Then Exit For
Cells(i, 1).Select
curString = Cells(i, 1).Value
nextString = Cells(i + 1, 1).Value
isDuplicate = WorksheetFunction.CountIf(Rng, Cells(i, 1).Value)
If isDuplicate > 1 Then
firstInstanceRow = i
Do Until Cells(i, 1).Offset(k, 0).Value <> nextString
'Cells(i, 1).Offset(k, 0).Select
lastInstanceRow = Cells(i, 1).Offset(k, 0).Row
k = k + 1
Loop
Cells(firstInstanceRow, 5).Formula = "=Combine(" & Range(Cells(firstInstanceRow + 1, 2), Cells(lastInstanceRow, 3)).Address(False, False) & ")" ' combine the results in one row so you have all the duplicates one after another
Cells(firstInstanceRow, 5).Copy
Cells(firstInstanceRow, 5).PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks:=False
Application.CutCopyMode = False
Selection.TextToColumns DataType:=xlDelimited, _ ' this is for converting comma delimited to columns
ConsecutiveDelimiter:=False, Semicolon:=True ' here you should change your delimiter to what you are using
Range(Rows(firstInstanceRow + 1), Rows(lastInstanceRow)).EntireRow.Delete
k = 0
lastRow = Cells(1, 1).End(xlDown).Row
End If
Next i
End With
End Sub
Function 1
Function Combine(WorkRng As Range, Optional Sign As String = ";") As String
'Update 20130815
Dim Rng As Range
Dim OutStr As String
For Each Rng In WorkRng
If Rng.Text <> ";" Then
OutStr = OutStr & Rng.Text & Sign
End If
Next
Combine = Left(OutStr, Len(OutStr) - 1)
End Function
So quick story:
Module 1 calls for the other modules, i did it this way to make things easier for the end-user so he doesn't see all the modules just needs to click one.
Module 2 removes any text from the selected cells
Module 3 finds the duplicates and puts them on one line delimited by what you select in the function module. And then deletes the duplicates row.
Function 1 takes the output of you selection and puts it on one row delimited.
That is all, thanks for everybody's help and i wish this will help others.
Related
I want to filter all the values except value in Array i.e. "B400", "A200", "C300".
I tried following code, none of the code is working
Dim rDataRange as Range
set rDataRange = Range("A1:P1000")
rDataRange.AutoFilter Field:=11, Criteria1:="<>" & Array("B400", "A200", "C300"), Operator:=xlFilterValues
rDataRange.AutoFilter Field:=11, Criteria1:=Array("<>B400", "<>A200", "<>C300"), Operator:=xlFilterValues
Please help me
Modified for your situation:
Option Explicit
Sub AutoFilterWorkaround()
Dim sht As Worksheet
Dim filterarr As Variant, tofindarr As Variant
Dim lastrow As Long, i As Long, j As Long, k As Long
Set sht = ThisWorkbook.Worksheets("Sheet1")
lastrow = sht.Cells(sht.Rows.Count, "A").End(xlUp).Row
'List the parts of the words you need to find here
tofindarr = Array("B400", "A200", "C300")
ReDim filterarr(0 To 0)
j = 0
For i = 2 To lastrow
If sht.Cells(i, 11).Value <> tofindarr(0) And _
sht.Cells(i, 11).Value <> tofindarr(1) And _
sht.Cells(i, 11).Value <> tofindarr(2) Then
filterarr(j) = sht.Cells(i, 11).Value
j = j + 1
ReDim Preserve filterarr(0 To j)
End If
Next i
'Filter on array
sht.Range("$A$1:$P$" & lastrow).AutoFilter Field:=11, Criteria1:=Array(filterarr), Operator:=xlFilterValues
End Sub
There is an easier way to accomplish this then using a filter.
Dim lRow As Long
With ThisWorkbook.Sheets(1)
lRow = .Range("K" & Rows.Count).End(xlUp).Row
For i = 2 To lRow
If .Cells(i, 11).Value = "A200" Or .Cells(i, 11).Value = "B400" Or .Cells(i, 11).Value = "C300" Then
.Cells(i, 11).EntireRow.Hidden = True
End If
Next i
End With
you could still use AutoFilter() in a sort of reverse mode:
Dim myRng As Range ' helper range variable
With Range("A1:P1000") ' reference wanted range to filter, header row included
.AutoFilter field:=11, Criteria1:=Array("B400", "A200", "C300"), Operator:=xlFilterValues ' filter on "not wanted" values
If Application.Subtotal(103, .Resize(, 1)) > 1 Then ' if any filtered cell other than header row
Set myRng = .Offset(1).Resize(.Rows.Count - 1).SpecialCells(xlCellTypeVisible) ' temporarily set 'myRng' to referenced range "not wanted" rows
.Parent.AutoFilterMode = False ' remove filters and show all rows
myRng.EntireRow.Hidden = True ' hide referenced range "not wanted" rows, leaving "wanted" rows only visible
With .Offset(1).Resize(.Rows.Count - 1).SpecialCells(xlCellTypeVisible) ' reference referenced range "wanted" rows
.Select
' do what you want with "wanted" rows
End With
.EntireRow.Hidden = False ' unhide all referenced range rows
Else
.Parent.AutoFilterMode = False ' remove filters
End If
End With
I would like to select the top 10 Values from Main table and paste in different range (E3) and REMAINING all values and PASTE and SUM in another range(I3)
I used the code below. It is working for Top 10 values, BUT for remaining,
when i am adding one more row in Main table, it is not working. Help me.
Private Sub CommandButton1_Click()
'Calculation for Top 10 Countries
Sheets("Sheet1").Range("C" & Rows.Count).End(xlUp).Offset(-9, -2).Resize(10, 3).Copy Sheets("Sheet1").Range("E3")
'Calculation for Remaining Countries
Range("A3:C14").Copy Range("I3")
Range("I15").Select
ActiveCell.FormulaR1C1 = "Remaining"
Range("J15").Select
ActiveCell.FormulaR1C1 = "=SUM(R[-12]C:R[-1]C)"
Range("K15").Select
ActiveCell.FormulaR1C1 = "=SUM(R[-12]C:R[-1]C)"
End Sub
Please try this code.
Option Explicit
Private Sub CommandButton1_Click()
Dim Rng As Range
Dim R As Long, Rl As Long ' last row
With Worksheets("Sheet1")
Rl = .Cells(.Rows.Count, "A").End(xlUp).Row
R = Application.Max(Rl - 9, 3)
' pick Top 10 Countries
Set Rng = Range(.Cells(R, "A"), .Cells(Rl, "C"))
Rng.Copy Destination:=.Cells(3, "E")
' pick remaining countries
If R > 3 Then
Set Rng = Range(.Cells(3, "A"), .Cells(R - 1, "C"))
Rng.Copy Destination:=.Cells(3, "I")
' write totals
Rl = .Cells(.Rows.Count, "I").End(xlUp).Row
Set Rng = Range(.Cells(3, "J"), .Cells(Rl, "J"))
Rl = Rl + 1
With .Cells(Rl, "I")
.Value = "Remaining"
.HorizontalAlignment = xlRight
.Font.Bold = True
End With
With .Cells(Rl, "J")
.Value = Application.Sum(Rng)
.HorizontalAlignment = xlCenter
.Font.Bold = True
End With
With .Cells(Rl, "K")
.Value = Application.Sum(Rng.Offset(0, 1))
.HorizontalAlignment = xlCenter
.Font.Bold = True
End With
End If
End With
End Sub
Private Sub CommandButton1_Click()
Dim lr As Long
Dim pr As Long
With Sheets("Sheet1")
lr = .Range("A" & Rows.Count).End(xlUp).Row
'Calculation for Top 10 Countries
.Range("A" & (lr - 10) & ":C" & lr).Copy .Range("E3")
'Calculation for Remaining Countries
.Range("A3:C" & (lr - 11)).Copy .Range("I3")
pr = .Range("A3:C" & (lr - 11)).Rows.Count + 3
.Range("I" & pr).Value = "Remaining"
.Range("J" & pr).FormulaR1C1 = "=SUM(R[-12]C:R[-1]C)"
.Range("K" & pr).FormulaR1C1 = "=SUM(R[-12]C:R[-1]C)"
End With
End Sub
The code below first sorts the main table by country (hard-coded option), then creates 2 copies of the sorted table in columns E and I sorted descending or ascending (hard-coded option), and deletes the part in each which isn't needed. The user can choose the year by which the ranking is to be determined, and the program allows for more years to be added to the main table and processed without change of code. You may wish to change the name of the worksheet in the code.
Option Explicit
Private Sub CommandButton1_Click()
' 14 Nov 2017
Dim Ws As Worksheet
Dim ClmCount As Long
Dim SortYear As Long ' = column in main table
Dim SortOrder As XlSortOrder
Dim Rng As Range
Dim Rl As Long, Rend As Long ' last row
Dim R As Long, C As Long
Set Ws = Worksheets("Deepak")
SortYear = YearToSort(Ws)
If SortYear Then ' exit if cancelled
Application.ScreenUpdating = False
With Ws
Rl = .Cells(.Rows.Count, "A").End(xlUp).Row
If Rl > 3 Then ' skip, if no list
ClmCount = MainTableColumnsCount(Ws)
' === Sorting the main table
' you can sort on another column, in another order
' or skip the sort entirely
' to skip remove these two lines of code
Set Rng = Range(.Cells(3, "A"), .Cells(Rl, ClmCount))
SortRange Rng, 1, xlAscending ' sort Main by country (column 1)
' === set the sort order for Lists 1 & 2 here:-
SortOrder = xlAscending ' Alt: change for xlDescending
SheetSetup Ws, SortYear, SortOrder ' create sorted copies
' List 1: delete all but the top 10
C = ClmCount + 2
R = IIf(SortOrder = xlAscending, 3, 13)
Rend = IIf(SortOrder = xlAscending, Rl - 10, Rl)
Set Rng = Range(.Cells(R, C), .Cells(Rend, C + ClmCount - 1))
Rng.Delete Shift:=xlUp
' List 2: delete the top 10
C = 2 * (ClmCount + 1) + 1
R = IIf(SortOrder = xlAscending, Rl - 9, 3)
Rend = IIf(SortOrder = xlAscending, Rl, 12)
Set Rng = Range(.Cells(R, C), .Cells(Rend, C + ClmCount - 1))
Rng.Delete Shift:=xlUp
' write totals
Rl = .Cells(.Rows.Count, C).End(xlUp).Row
With .Cells(Rl + 1, C)
.Value = "Remaining"
.HorizontalAlignment = xlRight
.Font.Bold = True
End With
For C = (C + 1) To (C + ClmCount - 1)
Set Rng = Range(.Cells(3, C), .Cells(Rl, C))
With .Cells(Rl + 1, C)
.Value = Application.Sum(Rng)
.HorizontalAlignment = xlCenter
.Font.Bold = True
End With
Next C
End If
End With
Application.ScreenUpdating = True
End If
End Sub
Private Sub SortRange(Rng As Range, _
SortColumn As Long, _
SortOrder As XlSortOrder)
' 14 Nov 2017
With Rng.Worksheet.Sort
.SortFields.Clear
.SortFields.Add Key:=Rng.Columns(SortColumn), _
SortOn:=xlSortOnValues, _
Order:=SortOrder, _
DataOption:=xlSortNormal
.SetRange Rng
.Header = xlNo
.MatchCase = False
.Orientation = xlTopToBottom
.SortMethod = xlPinYin
.Apply
End With
End Sub
Private Function YearToSort(Ws As Worksheet) As Long
' 14 Nov 2017
' return the column number of the main table
' return 0 if cancelled
Dim Fun As Long
Dim Rng As Range
Dim UserInput As String
Set Rng = Ws.Range(Cells(2, 2), Cells(2, MainTableColumnsCount(Ws)))
' use B2 as default
Do
UserInput = InputBox("Enter the year to sort by:", _
"Select a year", Rng.Cells(1).Value)
If UserInput = "" Then Exit Do
On Error Resume Next
Fun = Application.Match(CLng(UserInput), Rng, 0)
If Err Then
MsgBox "There is no data for year " & UserInput & "." & vbCr & _
"Please enter an available year.", _
vbInformation, "Invalid input"
UserInput = ""
On Error GoTo 0
End If
Loop While UserInput = ""
YearToSort = Fun + 1
End Function
Private Sub SheetSetup(Ws As Worksheet, _
SortYear As Long, _
SortOrder As XlSortOrder)
' 14 Nov 2017
Const Captions As String = "Top 10 countries,All other countries"
Dim Rng As Range, SortRng As Range
Dim ClmCount As Long
Dim Rl As Long ' last row
Dim C As Long
Dim i As Long
With Ws
Rl = .Cells(.Rows.Count, 1).End(xlUp).Row
ClmCount = MainTableColumnsCount(Ws)
C = .UsedRange.Columns.Count
If C > ClmCount Then
' delete all existing except main table
Set Rng = Range(.Cells(1, ClmCount + 1), .Cells(Rl, C))
Rng.Cells.Delete Shift:=xlUp
End If
Set Rng = Range(.Cells(1, 1), .Cells(Rl, ClmCount))
' create two copies of the main table
For i = 1 To 2
C = (ClmCount + 1) * i + 1
Rng.Copy Destination:=.Cells(1, C)
.Cells(1, C + 1).Value = Split(Captions, ",")(i - 1)
Set SortRng = Range(.Cells(3, C), .Cells(Rl, C + ClmCount - 1))
SortRange SortRng, SortYear, SortOrder
Next i
End With
End Sub
Private Function MainTableColumnsCount(Ws As Worksheet) As Long
' 14 Nov 2017
Dim Fun As Long
Do
Fun = Fun + 1
Loop While Len(Ws.Cells(2, Fun).Value)
MainTableColumnsCount = Fun - 1
End Function
You could do it with formulas as well. In the G3 cell type:
=LARGE(C$3:C$200, ROW()-2)
for finding the top country. In F3 and E3 insert:
=INDEX(B$3:B$200, MATCH(G3,C$3:C$200,0))
and
=INDEX(A$3:A$200, MATCH(G3,C$3:C$200,0))
respectively. Then drag then down to 12th row. You have top 10 now. In the cell K3 type:
=IFERROR(LARGE(C$3:C$200, ROW()+8),"")
and in J3 and I3:
=IFERROR(INDEX(B$3:B$200, MATCH(K3,C$3:C$200,0)),"")
and
=IFERROR(INDEX(A$3:A$200, MATCH(K3,C$3:C$200,0)),"")
Then drag then down several screens. There is less than 200 countries and territories on the world, so it should be enough. If there is no macros, you don'tneed the button, everything will update on fly.
In the each cell in a column I have this information in the cells:
A1 values:
Depth=standard;Size=1 section;Doors=hinged solid;Interior configuration=shelves;Compressor HP=1/2 HP;Interior finish=stainless steel;Exterior finish=stainless steel;Refrigeration=top mount self-contained
A2 values:
Top openings= 6 pan;Size=1 section;Compressor HP=1/6 HP;Style=drawers;Exterior finish=stainless steel;Interior finish=stainless steel;Refrigeration=rear mounted
A3,A4,A5 etc all follow similar formats
I need some method of abstracting out the following information into its own cells:
I need each semicolon separated value to be checked if there is a column name for it already, if not, make a new column and put all corresponding values where they need to be
I thought about using text->columns and then using index/match but I haven't been able to get my match criteria to work correctly. Was going to do this for each unique column. Or do I need to use VBA?
You could go with something like this, though you'll have to update the sheet name and probably where you want the final data located.
Sub SplitCell()
Dim DataFromCell, FoundCell
Dim Testing, Counted, LastCol
For Each c In Range(Range("A1"), Range("A" & Rows.count).End(xlUp))
Testing = Split(c.Value, ";")
Range("B" & c.row + 1).Value = "A" & c.row
Counted = UBound(Testing)
For Each x In Testing
DataFromCell = Split(x, "=")
With Sheet2
Set FoundCell = .Cells.Find(What:=DataFromCell(0), after:=.Cells(1, 2), _
LookIn:=xlValues, lookat:=1, searchorder:=xlByColumns, searchdirection:=xlNext, _
MatchCase:=False, searchformat:=False)
End With
If Not FoundCell Is Nothing Then
Cells(c.row + 1, FoundCell.Column).Value = DataFromCell(1)
End If
If FoundCell Is Nothing Then
LastCol = Sheet2.Cells(1, Sheet2.Columns.count).End(xlToLeft).Column
Cells(1, LastCol + 1).Value = DataFromCell(0)
Cells(c.row + 1, LastCol + 1).Value = DataFromCell(1)
End If
Next x
Next c
End Sub
Edit
Since the above was giving you errors you could try this one:
Sub SplitCell()
Dim DataFromCell, FoundCell
Dim Testing, Counted, LastCol
For Each c In Range(Range("A1"), Range("A" & Rows.count).End(xlUp))
Testing = Split(c.Value, ";")
Range("B" & c.row + 1).Value = "A" & c.row
Counted = UBound(Testing)
For Each x In Testing
DataFromCell = Split(x, "=")
LastCol = Sheet2.Cells(1, Sheet2.Columns.count).End(xlToLeft).Column
With Sheet2
FoundCell = Application.Match(DataFromCell(0), Range(Cells(1, 2), Cells(1, LastCol)), 0)
'Set FoundCell = .Cells.Find(What:=DataFromCell(0), after:=.Cells(1, 2), _
LookIn:=xlValues, lookat:=1, searchorder:=xlByColumns, searchdirection:=xlNext, _
MatchCase:=False, searchformat:=False)
End With
If Not IsError(FoundCell) Then
Cells(c.row + 1, FoundCell + 1).Value = DataFromCell(1)
End If
If IsError(FoundCell) Then
Cells(1, LastCol + 1).Value = DataFromCell(0)
Cells(c.row + 1, LastCol + 1).Value = DataFromCell(1)
End If
Next x
Next c
End Sub
Only changed a few things so that it is using Match instead of Find
My solution below works as intended but the data wasn't as formatted as I originally thought.
Option Explicit
Private Sub Auto_Open()
MsgBox ("Welcome to the delimiter file set.")
End Sub
'What this program does:
'http://i.imgur.com/7MVuZLt.png
Sub DelimitFilter()
Dim curSpec As String
Dim curSpecArray() As String
Dim i As Integer, IntColCounter As Integer, iCounter As Integer, argCounter As Integer
Dim WrdString0 As String, WrdString1 As String
Dim dblColNo As Double, dblRowNo As Double
Worksheets(1).Activate
'Reference to cell values that always have data associated to them
Range("W2").Activate
'checks for number of arguments to iterate through later
Do
If ActiveCell.Value = "" Then Exit Do
ActiveCell.Offset(1, 0).Activate
argCounter = argCounter + 1
Loop
'Check # of arguments
Debug.Print (argCounter)
'Values to delimit
Range("X2").Activate
IntColCounter = 1
'Loop each row argument
For iCounter = 0 To argCounter
'Set var to activecell name
dblColNo = ActiveCell.Column
dblRowNo = ActiveCell.Row
'Grab input at active cell
curSpecArray() = Split(ActiveCell.Value, ";")
'Ignore empty rows
If Not IsEmpty(curSpecArray) Then
'Iterate every delimited active cell value at that row
For i = LBound(curSpecArray) To UBound(curSpecArray)
'Checks for unique attribute name, if none exists, make one
WrdString0 = Split(curSpecArray(i), "=")(0)
'a large range X1:ZZ1 is used as there are many unique column names
If IsError(Application.Match(WrdString0, Range("X1:ZZ1"), 0)) Then 'if NOT checks if value exists
Cells(1, dblColNo + IntColCounter).Value = WrdString0
IntColCounter = IntColCounter + 1
End If
'Output attribute value to matching row and column
WrdString1 = Trim(Split(curSpecArray(i), "=")(1))
Debug.Print (WrdString1)
Cells(dblRowNo, -1 + dblColNo + Application.Match(WrdString0, Range("X1:ZZ1"), 0)).Value = WrdString1
Next i
End If
'Iterate Next row value
ActiveCell.Offset(1, 0).Activate
Next iCounter
End Sub
So I have workbook with sheets named Contacts and Help. In Help sheet I have Button which shows inputbox and asks "What client you would like to find?"
When I input name like Samuel Smith. I would like that VBA would go to Contacts sheet and find me Samuel Smith and offset to one column right and copy the Firm where Samuel Smith works. Then paste it to Help sheet and find next Samuel Smith. I would love to do this even if there were 50 Samuel Smith's in Contacts! Just don't know how to do this so any help is much appreciated!
Thank you all for your answers in advance.
Below are my custom function, that can find and return the result in Array.
From the find result you should able to solve your problem.
Hope this help !
Sub test()
'The result will be on Column C, because offset = 1
Dim nItem, Found As Variant
Found = iFind("Concatenate", Columns(2), 1)
For Each nItem In Found
MsgBox nItem
Next
End Sub
Function iFind(ByVal findText As String, ByVal nColumn As Range, ByVal offsetColumn As Single, _
Optional ByVal startRow As Single = 1, Optional ByVal caseSensitive As Boolean = False) As Variant
'Return Array of Range
'nColumn - Column to find
'offsetColumn - offset column to return
Dim WBD As Workbook
Dim WSD As Worksheet
Dim lastRow, tCount, nCount, nRow, nCol, N As Single
Dim nColRng, dataRng As Range
Dim compare As VbCompareMethod
Dim nArray As Variant
ReDim nArray(0)
Set WSD = nColumn.Parent
'Ensure only on column selected to consider lastRow
Set nColRng = nColumn.Columns(1)
nCol = nColRng.Column
'Get the lastRow
On Error Resume Next
lastRow = startRow
lastRow = nColRng.Find("*", SearchOrder:=xlByRows, SearchDirection:=xlPrevious).Row
If lastRow < startRow Then lastRow = startRow
On Error GoTo 0
Set dataRng = Intersect(WSD.Range(WSD.Rows(startRow), WSD.Rows(lastRow)), nColRng)
tCount = Excel.Application.WorksheetFunction.CountIfs(dataRng, findText)
If tCount > 0 Then
nCount = 0
N = 0
Do While nCount < tCount
nRow = Excel.Application.Match(findText, dataRng, 0) + dataRng(1).Row - 1
If caseSensitive = True Then
compare = vbBinaryCompare
Else
compare = vbTextCompare
End If
'Add into array, only if matching case
If InStr(1, findText, WSD.Cells(nRow, nCol), compare) Then
ReDim Preserve nArray(N)
nArray(N) = WSD.Cells(nRow, nCol + offsetColumn)
N = N + 1
End If
nCount = nCount + 1
'Resize dataRng
Set dataRng = Intersect(WSD.Range(WSD.Rows(nRow + 1), WSD.Rows(lastRow)), nColRng)
Loop
End If
iFind = nArray
End Function
I worked on this hole night and now I know how to do this!
Option Explicit
'''''''
Dim Find_Inp As String
Dim Find As Variant
Dim Error_ As Integer
'''''''
Sub Test2()
On Error Resume Next
Sheet1.Select
Range("A8:G100").ClearContents
Find_Inp = InputBox("Please input Account!")
If Find_Inp = "" Then
Exit Sub
End If
MsgBox "This will take some time please wait."
Sheet2.Select
Call Macro1 'Sort macro
Call Find_Full
Exit Sub
End Sub
Function
Private Function Find_Full()
On Error GoTo ErrorHandler
'''''''
Dim Account_Column As Variant
Dim Result As Range, Result2 As Range
Dim LastAccount As Long
Dim NextAccount As Long
Dim Find_repeat As Integer
'''''''
Sheets("Contacts").Select
Account_Column = Range("G1").Select
Find = Cells.Find(What:=Find_Inp, After:=ActiveCell, LookIn:=xlValues, LookAt:= _
xlPart, SearchOrder:=xlByRows, SearchDirection:=xlNext, MatchCase:=False _
, SearchFormat:=False).Activate
Find_repeat:
If Find = True Then
Set Result = ActiveCell
LastAccount = Sheet1.Cells(Rows.Count, 3).End(xlUp).Row
NextAccount = LastAccount + 1
Result.Copy 'Where the name
Sheet1.Select
Range("C" & NextAccount).PasteSpecial xlPasteValuesAndNumberFormats
Result.Offset(0, -2).Copy 'Where the firm name is
Sheet1.Select
Range("C" & NextAccount).Offset(0, 1).PasteSpecial xlPasteValuesAndNumberFormats
Sheet2.Select
Result.Offset(0, -1).Copy 'Where the email is
Sheet1.Select
Range("C" & NextAccount).Offset(0, 2).PasteSpecial xlPasteValuesAndNumberFormats
Sheet2.Select
Result.Offset(0, 9).Copy 'Where the phone number
Sheet1.Select
Range("C" & NextAccount).Offset(0, -2).PasteSpecial xlPasteValuesAndNumberFormats
Sheet2.Select
Result.Offset(0, 10).Copy 'Where the work number is
Sheet1.Select
Range("C" & NextAccount).Offset(0, -1).PasteSpecial xlPasteValuesAndNumberFormats
Sheet2.Select
Result.Offset(0, 4).Copy 'Where the firm addres is
Sheet1.Select
Range("C" & NextAccount).Offset(0, 3).PasteSpecial xlPasteValuesAndNumberFormats
Sheet2.Select
Result.Offset(0, 5).Copy 'Where the title is
Sheet1.Select
Range("C" & NextAccount).Offset(0, 4).PasteSpecial xlPasteValuesAndNumberFormats
Error_ = 0
End If
Sheet2.Select
Result.Offset(1, 0).Select
Set Result2 = ActiveCell
If Result2 = Find_Inp Then
GoTo Find_repeat
Else
Sheet1.Select
Range("A1").Select
End If
ErrorHandler:
If Error_ = 1 Then
Sheet1.Select
Range("A1").Select
MsgBox "Account was not found! Try again."
End If
Error_ = 1
End Function
Sort Macro
Private Sub Macro1()
'
' Macro1 Macro
'
'
Dim Lastrow As Long
Lastrow = Sheet2.Cells(Rows.Count, 7).End(xlUp).Row
Application.CutCopyMode = False
ActiveWorkbook.Worksheets("Contacts").Sort.SortFields.Clear
ActiveWorkbook.Worksheets("Contacts").Sort.SortFields.Add Key:=Range("G1"), _
SortOn:=xlSortOnValues, Order:=xlAscending, DataOption:=xlSortNormal
With ActiveWorkbook.Worksheets("Contacts").Sort
.SetRange Range("A2:AJ2106")
.Header = xlNo
.MatchCase = False
.Orientation = xlTopToBottom
.SortMethod = xlPinYin
.Apply
End With
Range("A1").Select
End Sub
I have a simple piece of code that used to burn through 45,000 rows of data in the blink of an eye and now it takes a very long time (~15 minutes). I have read through some similar problems but wanted to post the code since it is so basic. This code sums the individual weights of each item (one item per row) of an order and then populates a cell for each item with the total amount. It goes from top to bottom to get the total and then from bottom to top filling in the blanks. What am I missing?
Sub FillInTotalWeight()
'
' sort whole file by process order
'
'this macro sums all the children weights in a process order
'and then puts that total in column E for every child of the process order
'
Dim nLastRow As Long
Dim nRow As Long
Dim wtTot As Long
Dim nStop As Long
'
'determine the last row
'
nLastRow = ActiveSheet.UsedRange.Rows.Count
'
'sort by process order
'
ActiveWorkbook.Worksheets("zpr2013b").Sort.SortFields.Clear
ActiveWorkbook.Worksheets("zpr2013b").Sort.SortFields.Add _
Key:=Range(Cells(1, "D"), Cells(nLastRow, "D")), _
SortOn:=xlSortOnValues, Order:=xlAscending, DataOption:=xlSortNormal
With ActiveWorkbook.Worksheets("zpr2013b").Sort
.SetRange Range(Cells(1, "A"), Cells(nLastRow, "q"))
.Header = xlYes
.MatchCase = False
.Orientation = xlTopToBottom
.SortMethod = xlPinYin
.Apply
End With
wtTot = Cells(2, "B").Value
'
'go top to bottom and put the total weight of each process order
'in the row of the last coil produced
'
For nRow = 2 To nLastRow
If Cells(nRow, "D").Value = Cells(nRow + 1, "D").Value Then
wtTot = wtTot + Cells(nRow + 1, "B").Value
Else
Cells(nRow, "E").Value = wtTot
wtTot = Cells(nRow + 1, "B").Value
End If
Next nRow
'
'go bottom to top and fill in all the blanks of the other coils
'
For x = nLastRow To 2 Step -1
If Cells(x, "E").Value = "" Then
Cells(x, "E").Value = Cells(x + 1, "E").Value
End If
Next x
End Sub
I would recommend using this code instead. It should run much faster for you and will accomplish the same thing:
Sub FillInTotalWeight()
Dim ws As Worksheet
Set ws = ActiveWorkbook.Sheets("zpr2013b")
ws.UsedRange.Sort Intersect(ws.UsedRange, ws.Columns("D")), xlAscending, Header:=xlYes
With Range("E2", ws.Cells(Rows.Count, "D").End(xlUp).Offset(, 1))
.Formula = "=SUMIF(D:D,D" & .Row & ",B:B)"
.Value = .Value
End With
End Sub