Extracting Text from a cell - excel

I have a search function which works perfectly for searching for Exact Numerical values, However I need to adapt it so it searches for text within a cell and only extracts that text. For example it searches column 7. In column 7 there may be a cell containing the words Interface - HPT, SAS, LPT Ideally I would like to search for the word Interface - HPT then extract Only this text from the cell. I also need the search function to be able to do this for multiple different values. So for example run a search for Interface - HPT
Interface - SAS and Interface LPT separate from each other. Is this Possible ?
Here is the code I have at the moment:
Sub InterfaceMacro()
Dim Headers() As String: Headers = _
Split("Target FMECA,Part I.D,Line I.D,Part No.,Part Name,Failure Mode,Assumed System Effect,Assumed Engine Effect", ",")
Worksheets.Add().Name = "Interface"
Dim wsInt As Worksheet: Set wsInt = Sheets("Interface")
wsInt.Move after:=Worksheets(Worksheets.Count)
wsInt.Cells.Clear
Application.ScreenUpdating = False
With wsFHA
For i = 0 To UBound(Headers)
.Cells(2, i + 2) = Headers(i)
.Columns(i + 2).EntireColumn.AutoFit
Next i
.Cells(1, 2) = "Interface TABLE"
.Range(.Cells(1, 2), .Cells(1, UBound(Headers) + 2)).MergeCells = True
.Range(.Cells(1, 2), .Cells(1, UBound(Headers) + 2)).HorizontalAlignment = xlCenter
.Range(.Cells(1, 2), .Cells(2, UBound(Headers) + 2)).Font.Bold = True
End With
Dim SourceCell As Range, FirstAdr As String
Dim RowCounter As Long: RowCounter = 3
Dim SearchTarget() As String
SearchTarget = Split("9.1,18.0", ",")
For i = 0 To UBound(SearchTarget)
If Worksheets.Count > 1 Then
For j = 1 To Worksheets.Count - 1
With Sheets(j)
Set SourceCell = .Columns(7).Find(SearchTarget(i), LookAt:=xlWhole)
If Not SourceCell Is Nothing Then
FirstAdr = SourceCell.Address
Do
wsInt.Cells(RowCounter, 2).Value = SearchTarget(i)
wsInt.Cells(RowCounter, 3).Value = .Cells(SourceCell.Row, 6).Value
wsInt.Cells(RowCounter, 4).Value = .Cells(3, 10).Value
wsInt.Cells(RowCounter, 5).Value = .Cells(2, 10).Value
wsInt.Cells(RowCounter, 6).Value = .Cells(SourceCell.Row, 2).Value
For k = 0 To SourceCell.Row - 1
If .Cells(SourceCell.Row - k, 3).Value <> "continued." Then
wsFHA.Cells(RowCounter, 7).Value = .Cells(SourceCell.Row - k, 3).Value
Exit For
End If
Next k
wsInt.Cells(RowCounter, 8).Value = .Cells(SourceCell.Row, 14).Value
Set SourceCell = .Columns(7).FindNext(SourceCell)
RowCounter = RowCounter + 1
Loop While Not SourceCell Is Nothing And SourceCell.Address <> FirstAdr
End If
End With
Next j
End If
Next i
End Sub
The part I believe needs editing is this section
Dim SourceCell As Range, FirstAdr As String
Dim RowCounter As Long: RowCounter = 3
Dim SearchTarget() As String
SearchTarget = Split("9.1,18.0", ",")
For i = 0 To UBound(SearchTarget)
If Worksheets.Count > 1 Then
For j = 1 To Worksheets.Count - 1
With Sheets(j)
Set SourceCell = .Columns(7).Find(SearchTarget(i), LookAt:=xlWhole)
If Not SourceCell Is Nothing Then
FirstAdr = SourceCell.Address

You can define the array to search the same way as you define it for numbers.
To search also part of the cell content you need to change .Find(SearchTarget(i), LookAt:=xlWhole) to .Find(SearchTarget(i), LookAt:=xlPart).
VBA looks in formulas / results the same way as it works in Find / Replace dialog. (set .LookIn to either xlValues or xlFormulas)

Related

How to compare two sets of strings?

The code is supposed to compare string A1 and A2 with string B1 and B2 respectively.
If it doesn't match, insert a line, copy B1 and B2 data to A1 and A2 respectively and paint the entire row red.
Otherwise check if the value inside C1, C2, C3 and C4 is the same as D1, D2, D3 and D4.
If yes, do nothing, otherwise paint the C cell with yellow.
The issue seems to be with the string compare.
It creates rows and paints stuff seemingly randomly.
Option Explicit
Sub CompareValues()
Dim ws1 As Worksheet, ws2 As Worksheet
Dim ws1EndRow As Long, ws2EndRow As Long, i As Long
Dim dbAMarca As String, dbASubGrupo As String
Dim dbAQtddVendas As Range, dbAValorVendas As Range
Dim dbAQtddEstoque As Range, dbAValorEstoque As Range
Dim dbBMarca As String, dbBSubGrupo As String
Dim dbBQtddVendas As Range, dbBValorVendas As Range
Dim dbBQtddEstoque As Range, dbBValorEstoque As Range
Set ws1 = Application.Workbooks("1.xlsx").Sheets("Sheet1")
Set ws2 = Application.Workbooks("2.xls").Sheets("Sheet2")
i = 4
ws1EndRow = ws1.UsedRange.Rows(ws1.UsedRange.Rows.Count).Row
While i < ws1EndRow
dbASubGrupo = ws1.Cells(i, "D")
dbAMarca = ws1.Cells(i, "E")
Set dbAQtddVendas = ws1.Cells(i, "F")
Set dbAValorVendas = ws1.Cells(i, "G")
Set dbAQtddEstoque = ws1.Cells(i, "M")
Set dbAValorEstoque = ws1.Cells(i, "O")
dbBSubGrupo = ws2.Cells(i - 1, "H")
dbBMarca = ws2.Cells(i - 1, "J")
Set dbBQtddVendas = ws2.Cells(i - 1, "Q")
Set dbBValorVendas = ws2.Cells(i - 1, "R")
Set dbBQtddEstoque = ws2.Cells(i - 1, "AF")
Set dbBValorEstoque = ws2.Cells(i - 1, "AI")
If Not (StrComp(dbAMarca, dbBMarca, 1) And StrComp(dbASubGrupo, dbBSubGrupo, 1)) Then
ws1.Rows(i).EntireRow.Insert
ws1.Rows(i).EntireRow.Interior.Color = vbRed
ws1.Cells(i, "D").Value = ws2.Cells(i - 1, "H").Value
ws1.Cells(i, "E").Value = ws2.Cells(i - 1, "J").Value
ws1EndRow = ws1.UsedRange.Rows(ws1.UsedRange.Rows.Count).Row
Else
If Not dbAQtddVendas.Value = dbBQtddVendas.Value Then
dbAQtddVendas.Interior.Color = vbYellow
End If
If Not dbAValorVendas.Value = dbBValorVendas.Value Then
dbAValorVendas.Interior.Color = vbYellow
End If
If Not dbAQtddEstoque.Value = dbBQtddEstoque.Value Then
dbAQtddEstoque.Interior.Color = vbYellow
End If
If Not dbAValorEstoque.Value = dbBValorEstoque.Value Then
dbAValorEstoque.Interior.Color = vbYellow
End If
End If
i = i + 1
Wend
End Sub
StrComp returns a numeric value not a boolean value, this changes how it works with Not operator. If your goal is to check whether the two are exact match you can replace the string compare statement with the following:
If dbAMarca<>dbBMarca and dbASubGrupo<>dbBSubGrupo Then
Ended up fixing it myself. There were many issues with the original code, and now they're all fixed including the one SaintSnowmad pointed out. Here's the final (working) code in case anyone needs something similar in the future.
Option Explicit
Sub CompareValues()
Dim ws1 As Worksheet, ws2 As Worksheet
Dim ws1EndRow As Long, ws2EndRow As Long
Dim i As Long, j As Long, k As Long
Dim dbAMarca As Range, dbASubGrupo As Range
Dim dbAQtddVendas As Range, dbAValorVendas As Range
Dim dbAQtddEstoque As Range, dbAValorEstoque As Range
Dim dbBMarca As Range, dbBSubGrupo As Range
Dim dbBQtddVendas As Range, dbBValorVendas As Range
Dim dbBQtddEstoque As Range, dbBValorEstoque As Range
Set ws1 = Application.Workbooks("1.xlsx").Sheets("Sheet1")
Set ws2 = Application.Workbooks("2.xls").Sheets("Sheet2")
i = 4
j = 0
k = 0
ws1EndRow = ws1.UsedRange.Rows(ws1.UsedRange.Rows.Count).Row
While i < ws1EndRow
Set dbASubGrupo = ws1.Cells(i, "D")
Set dbAMarca = ws1.Cells(i, "E")
Set dbAQtddVendas = ws1.Cells(i, "F")
Set dbAValorVendas = ws1.Cells(i, "G")
Set dbAQtddEstoque = ws1.Cells(i, "M")
Set dbAValorEstoque = ws1.Cells(i, "O")
Set dbBSubGrupo = ws2.Cells(i - 1 - k, "H")
Set dbBMarca = ws2.Cells(i - 1 - k, "J")
Set dbBQtddVendas = ws2.Cells(i - 1 - k, "Q")
Set dbBValorVendas = ws2.Cells(i - 1 - k, "R")
Set dbBQtddEstoque = ws2.Cells(i - 1 - k, "AF")
Set dbBValorEstoque = ws2.Cells(i - 1 - k, "AI")
If dbAMarca.Value <> dbBMarca.Value Or dbASubGrupo.Value <> dbBSubGrupo.Value Then
For j = i To i + 10
If ws1.Cells(i, "D").Value = ws2.Cells(j - k, "H").Value And ws1.Cells(i, "E").Value = ws2.Cells(j - k, "J") Then
ws1.Rows(i).EntireRow.Insert
ws1.Rows(i).EntireRow.ClearFormats
ws1.Rows(i).EntireRow.Interior.Color = vbRed
ws1.Cells(i, "D").Value = ws2.Cells(j - 1 - k, "H").Value
ws1.Cells(i, "E").Value = ws2.Cells(j - 1 - k, "J").Value
ws1EndRow = ws1.UsedRange.Rows(ws1.UsedRange.Rows.Count).Row
Exit For
End If
If j = i + 10 Then
ws1.Rows(i).EntireRow.Interior.Color = vbCyan
k = k + 1
End If
Next
Else
If Not dbAQtddVendas.Value = dbBQtddVendas.Value Then
dbAQtddVendas.Interior.Color = vbYellow
End If
If Not dbAValorVendas.Value = dbBValorVendas.Value Then
dbAValorVendas.Interior.Color = vbYellow
End If
If Not dbAQtddEstoque.Value = dbBQtddEstoque.Value Then
dbAQtddEstoque.Interior.Color = vbYellow
End If
If Not dbAValorEstoque.Value = dbBValorEstoque.Value Then
dbAValorEstoque.Interior.Color = vbYellow
End If
End If
i = i + 1
Wend
End Sub

VBA Excel: enumerate total number of duplicates. Count and sum

On the left is the hypothetical database. On the right is the result I would like to obtain.
I would like to print all of the items of type B, as well as the sum and the count.
I'm stuck and I'm not able to go ahead. Could you please help me out? Thanks.
Private Sub CommandButton1_Click()
Dim dicDistincts As Scripting.Dictionary, _
dicDuplicates As Scripting.Dictionary
Set dicDistincts = New Scripting.Dictionary
Set dicDuplicates = New Scripting.Dictionary
Dim i As Integer
For i = 2 To 10
If Cells(i, 1).Value = "B" Then
If Not dicDistincts.Exists(Cells(i, 2).Value) Then
dicDistincts.Add Key:=Cells(i, 2).Value, Item:=Cells(i, 2).Value
Else
dicDuplicates.Add Key:=Cells(i, 2).Value, Item:=Cells(i, 2).Value
End If
End If
Next i
For i = 0 To dicDuplicates.Count - 1
Cells(i + 1, 9).Value = WorksheetFunction.CountIfs(Range("a2:a10"), "B", Range("b2:b10"), dicDistincts.keys(i))
Next i
End Sub
EDIT: I tried with countifs but it return 0 for banana, apple and strawberry
EDIT 2: I corrected the countifs. Now it works.
If you must use dictionaries then you could do this with a single dictionary, storing the counts and quantities as array as the values in the dictionary.
Private Sub CommandButton1_Click()
Dim dic As Scripting.Dictionary
Dim arrData()
Dim i As Long
Dim ky As Variant
Set dic = New Dictionary
For i = 2 To 10
If Cells(i, 1).Value = "B" Then
ky = Cells(i, 2).Value
If Not dic.Exists(ky) Then
arrData = Array(1, Cells(i, 3).Value)
Else
arrData = dic(ky)
arrData = Array(arrData(0) + 1, arrData(1) + Cells(i, 3).Value)
End If
dic(ky) = arrData
End If
Next i
Range("A1:C1").Copy Range("E1:G1")
For i = 0 To dic.Count - 1
Range("E" & i + 2) = dic.Keys(i)
Range("F" & i + 2).Resize(, 2) = dic.Items(i)
Next i
End Sub
Unique Sum and Unique Count with Double Dictionary
Option Explicit
Private Sub CommandButton1_Click()
Dim rg As Range
With Range("A1").CurrentRegion
Set rg = .Resize(.Rows.Count - 1).Offset(1)
End With
Dim Data As Variant: Data = rg.Value
Dim cDict As Object: Set cDict = CreateObject("Scripting.Dictionary")
Dim sDict As Object: Set sDict = CreateObject("Scripting.Dictionary")
Dim i As Long
For i = 1 To UBound(Data, 1)
If Data(i, 1) = "B" Then
cDict(Data(i, 2)) = cDict(Data(i, 2)) + 1 ' Count
sDict(Data(i, 2)) = sDict(Data(i, 2)) + Data(i, 3) ' Sum
End If
Next i
ReDim Data(1 To cDict.Count, 1 To 3)
i = 0
Dim Key As Variant
For Each Key In cDict.Keys
i = i + 1
Data(i, 1) = Key
Data(i, 2) = sDict(Key)
Data(i, 3) = cDict(Key)
Next Key
With Range("E2").Resize(, 3)
.Resize(i).Value = Data
.Resize(.Worksheet.Rows.Count - .Row - i + 1).Offset(i).ClearContents
End With
End Sub
This should work it uses loops through all bs and addes them if to the other list
Sub countBs()
Dim Bs As Range 'list of the line of all Bs
Dim B As Range 'each indiviual b in the B list
Dim Item As Range 'each indivual item
Dim adder As Range 'resturns nothing if b not fond in times
Set Bs = Range("a2", Range("a2").End(xlDown)) 'you can also change this ofcourse to a specifici range or user selected
For Each B In Bs
If B = "B" Then
Set adder = Range("g2", Range("g2").End(xlDown)).Find(B.Offset(0, 1))
If adder Is Nothing Then
If Range("g2") = "" Then
Set Item = Range("g2")
Else
Set Item = Range("g1").End(xlDown).Offset(1, 0)
End If
Item.Resize(1, 2).Value = B.Offset(0, 1).Resize(1, 2).Value
Item.Offset(0, 2) = 1
Else
adder.Offset(0, 1).Value = adder.Offset(0, 1).Value + B.Offset(0, 2).Value
adder.Offset(0, 2).Value = adder.Offset(0, 2).Value + 1
End If
End If
Next B
End Sub

How to find a value in column and paste ranges from other worksheets into its adjacent columns

The end goal for my project is that the user will be able to select a value from a ComboBox to fill out a report on a Summary Tab. The report will consist of 3, 3 cell ranges (divided into 3 1x3 ranges on 3 separate worksheets).
I want to find the row with the value the user selected in the ComboBox and then set the 9 cells to the right of that value equal to the values in the range mentioned previously.
I've tried a couple of different ways of doing this, but I'll include the code I most recently worked on below:
Private Sub OKButton1_Click()
Dim userValue, rangeOne, rangeTwo, rangeThree
Dim i As Long
i = 4
userValue = ComboBox1.Value
Set rangeOne = Sheets("Sheet2").Range(Range("F23:H23")
Set rangeTwo = Sheets("Sheet3").Range("F90:H90")
Set rangeThree = Sheets("Sheet4").Range("F17:H17")
While Sheets("Reports").Range(cells(i,1)).Value <> ""
If Sheets("Reports").Range(cells(i, "A")).Value = "userValue" Then
Set Sheets("Reports").Range(Cells(i, "B:E")) = rangeOne
Set Sheets("Reports").Range(Cells(i, "F:I")) = rangeOne
Set Sheets("Reports").Range(Cells(i, "J:M")) = rangeOne
End If
i = i + 1
Wend
Unload UserForm2
End Sub
Any Ideas on how I can improve this or get it working? Currently getting 1004 errors.
Two words of advice when working with excel:
always make variables for each sheet/book you need to work with
Avoid using ranges and objects if you can. It is much easier to iterate over individual cells using an array and a for loop like I did below.
I was a bit confused on exactly what you needed done, so you will need to modify this slightly to fit your ranges/where you want the data to go. If you are confused or need further assistance let me know and I'll update this.
Dim userValue
Dim xrow As Long, ws1 As Worksheet, ws2 As Worksheet, ws3 as Worksheet, ws4 as Worksheet
Dim arrData() as variant
set ws1 = Worksheets("Report")
set ws2 = Worksheets("Sheet2")
set ws3 = Worksheets("Sheet3")
set ws4 = Worksheets("Sheet4")
userValue = ComboBox1.Value
xrow = 1
ws2.activate
'the InStr function checks if the first condition contains the second, and when it does, it returns 1, which in turn triggers the if statement
for x = 1 To ws2.Cells(rows.count, 1).end(xlup).row
if InStr(1, Cells(x, 1), userValue) > 0 Then
arrData(0) = ws2.Cells(x, 2).value
arrData(1) = ws2.Cells(x, 3).value
arrData(2) = ws2.Cells(x, 4).value
else:
end if
next x
ws3.activate
for x = 1 To ws3.Cells(rows.count, 1).end(xlup).row
if InStr(1, Cells(x, 1), userValue) > 0 Then
arrData(3) = ws3.Cells(x, 2).value
arrData(4) = ws3.Cells(x, 3).value
arrData(5) = ws3.Cells(x, 4).value
else:
end if
next x
ws4.activate
for x = 1 To ws4.Cells(rows.count, 1).end(xlup).row
if InStr(1, Cells(x, 1), userValue) > 0 Then
arrData(6) = ws4.Cells(x, 2).value
arrData(7) = ws4.Cells(x, 3).value
arrData(8) = ws4.Cells(x, 4).value
else:
end if
next x
ws1.activate
ws1.Cells(xrow, 1) = userValue
for y = 0 To 8
ws1.Cells(xrow, y+1).value = arrData(y)
next y
xrow = xrow + 1
For x = 1 To ws1.Cells(Rows.Count, 1).End(xlUp).Row
If InStr(1, Cells(x, 1), UserValue) > 0 Then
ws1.Cells(x, 2) = ws2.Cells(23, 6).Value
ws1.Cells(x, 3) = ws2.Cells(23, 7).Value
ws1.Cells(x, 4) = ws2.Cells(23, 8).Value
ws1.Cells(x, 6) = ws3.Cells(90, 6).Value
ws1.Cells(x, 7) = ws3.Cells(90, 7).Value
ws1.Cells(x, 8) = ws3.Cells(90, 8).Value
ws1.Cells(x, 10) = ws4.Cells(18, 6).Value
ws1.Cells(x, 11) = ws4.Cells(18, 7).Value
ws1.Cells(x, 12) = ws4.Cells(18, 8).Value
Else:
End If
Next x
The above is what I'm working with now in place of the while loop.

VBA code to not insert if data already in worksheet

I have the following macro which is so close to what I need. The issue I have is if the data is already in sheet2 it inserts a new line and the same data where as I don't want it duplicated. I have tried a few things but I cant quite get there
'start with sheet 1
Sheets(1).Activate
Dim rowStartSheet1, rowStartSheet2, lastRowSheet1, lastRowSheet2 As Integer
'change this variable if your row doesn't start on 2 as in this example for sheet1 and sheet2
rowStartSheet1 = 2
rowStartSheet2 = 2
'gets you the last row in sheet 1
lastRowSheet1 = Cells(Rows.Count, 1).End(xlUp).Row
'this entire for block is to check if a data row in sheet 1 is in sheet 2 and if so, copy and paste the rest of the data points
For i = rowStartSheet1 To lastRowSheet1
'case 1 where column C matches column A first time around (no duplicates)
'change this variable if sheet 2 starts on a different row
Sheets(2).Activate
lastRowSheet2 = Cells(Rows.Count, 1).End(xlUp).Row
'loops through sheet 2 column A to check if it matches what we want in sheet1 Column C
For ii = rowStartSheet2 To lastRowSheet2
'inputs if found first time around
If Sheets(1).Cells(i, 3) = Cells(ii, 1) And Cells(ii, 7) = "" Then
Cells(ii, 7) = Sheets(1).Cells(i, 1)
Cells(ii, 8) = Sheets(1).Cells(i, 2)
Exit For
'if sheet2 column G already has info in it, create a new row
ElseIf Sheets(1).Cells(i, 3) = Cells(ii, 1) And Cells(ii, 7) <> "" Then
Rows(ii).Select
Selection.Insert Shift:=xlShiftDown
Cells(ii, 1) = Sheets(1).Cells(i, 3)
Cells(ii, 7) = Sheets(1).Cells(i, 1)
Cells(ii, 8) = Sheets(1).Cells(i, 2)
Exit For
End If
Next ii
Next i
End Sub
All help appreciated
SHEET1
SHEET2
In my code below I refer to columns by their name (like "A", "B") instead of their number as you have done. This isn't intended as criticism. On the contrary, I much prefer to use numbers and usually declare them in enumerations. However, I felt that you might find my code more readable with the syntax I chose.
Sub CopyUniqueItems()
' 09 Aug 2017
Const RsFirst As Long = 2
Const RtFirst As Long = 2
Const Lot As Long = 1
Const Part As Long = 2
Const Col As Long = 3
Dim WsS As Worksheet ' S = Source
Dim WsT As Worksheet ' T = Target
Dim Rng As Range
Dim Itm As Variant
Dim Rs As Long, RsLast As Long ' Row / last row in WsS
Dim Rt As Variant, RtLast As Long ' Row / last row in WsT
Set WsS = Worksheets(1) ' { better to call by name
Set WsT = Worksheets(2) ' { like Worksheets("Sheet2")
RsLast = WsS.Cells(WsS.Rows.Count, "C").End(xlUp).Row
Application.ScreenUpdating = False
For Rs = RsFirst To RsLast
With WsS
Itm = .Range(.Cells(Rs, "A"), .Cells(Rs, "C")).Value
End With
With WsT
RtLast = .Cells(.Rows.Count, "A").End(xlUp).Row
With .Columns("A")
Set Rng = .Range(.Cells(RtFirst), .Cells(RtLast))
End With
On Error Resume Next
Rt = Application.Match(Itm(1, Lot), Rng, 0)
If IsError(Rt) Then
' not found
Rt = Application.Max(RtLast + 1, RtFirst)
Else
' exists already
Rt = Rt + RtFirst - 1
Do
If (.Cells(Rt, "G").Value = Itm(1, Part)) And _
(.Cells(Rt, "H").Value = Itm(1, Col)) Then
Rt = 0
Exit Do
Else
Rt = Rt + 1
End If
Loop While .Cells(Rt, "A").Value = Itm(1, Lot)
.Rows(Rt).Insert Shift:=xlShiftDown
End If
If Rt Then
.Cells(Rt, "A").Value = Itm(1, Lot)
.Cells(Rt, "G").Value = Itm(1, Part)
.Cells(Rt, "H").Value = Itm(1, Col)
End If
End With
Next Rs
Application.ScreenUpdating = True
End Sub
BTW, Dim rowStartSheet1, rowStartSheet2, lastRowSheet1, lastRowSheet2 As Integer declares only lastRowSheet2 as integer. All the others are undefined and therefore variants.

Excel VBA: How to transform this kind of cells?

I am not sure if the title is correct. Please correct me if you have a better idea.
Here is my problem: Please see the picture.
This excel sheet contains only one column, let's say ColumnA. In ColumnA there are some cells repeat themselvs in the continued cells twice or three times (or even more).
I want to have the excel sheet transformed according to those repeated cells. For those items which repeat three times or more, keep only two of them.
[Shown in the right part of the picture. There are three Bs originally, target is just keep two Bs and delete the rest Bs.]
It's a very difficult task for me. To make it easier, it's no need to delete the empty rows after transformation.
Any kind of help will be highly appreciated. Thanks!
#
Update:
Please see the picture. Please dont delete the items if they show again...
EDITED - SEE BELOW Try this. Data is assumed to be in "Sheet1", and ordered data is written to "Results". I named your repeted data (A, B, C, etc) as sMarker, and values in between as sInsideTheMarker. If markers are not consecutive, the code will fail.
Private Sub ReOrderData()
Dim lLastRow As Long
Dim i As Integer
Dim a As Integer
Dim j As Integer
Dim sMarker As String
Dim sInsideTheMarker As String
'Get number of rows with data:
lLastRow = Worksheets("Sheet1").Cells(Rows.Count, 1).End(xlUp).Row
j = 0
k = 1
a = 2
'Scan all rows with data:
For i = 1 To lLastRow
If (Worksheets("Sheet1").Cells(i + 1, 1).Value = Worksheets("Sheet1").Cells(i, 1).Value) Then 'If two consecutive cells holds the same value
j = j + 1
If j = 1 Then
k = k + 1
a = 2
sMarker = Worksheets("Sheet1").Cells(i, 1).Value
Worksheets("Results").Cells(k, 1).Value = sMarker
End If
Else 'If not same values in consecutive cells
sInsideTheMarker = Worksheets("Sheet1").Cells(i, 1).Value
Worksheets("Results").Cells(k, a).Value = sInsideTheMarker
a = a + 1
j = 0
End If
Next i
End Sub
EDITION: If you want results in the same sheet ("Sheet1"), and keep the empty rows for results to look exactly as your question, try the following
Private Sub ReOrderData()
Dim lLastRow As Long
Dim i As Integer
Dim a As Integer
Dim j As Integer
Dim sMarker As String
Dim sInsideTheMarker As String
'Get number of rows with data:
lLastRow = Worksheets("Sheet1").Cells(Rows.Count, 1).End(xlUp).Row
j = 0
k = 1
a = 5
'Scan all rows with data:
For i = 1 To lLastRow
If (Worksheets("Sheet1").Cells(i + 1, 1).Value = Worksheets("Sheet1").Cells(i, 1).Value) Then 'If two consecutive cells holds the same value
j = j + 1
If j = 1 Then
k = i
a = 5
sMarker = Worksheets("Sheet1").Cells(i, 1).Value
Worksheets("Sheet1").Cells(k, 4).Value = sMarker
End If
Else 'If not same values in consecutive cells
sInsideTheMarker = Worksheets("Sheet1").Cells(i, 1).Value
Worksheets("Sheet1").Cells(k, a).Value = sInsideTheMarker
a = a + 1
j = 0
End If
Next i
End Sub
If you can delete the values that have more than two counts, then I suggest that this might work:
Sub count_macro()
Dim a As Integer
Dim b As Integer
a = 1
While Cells(a, 1) <> ""
b = WorksheetFunction.CountIf(Range("A1:A1000"), Cells(a, 1))
If b > 2 Then
Cells(a, 1).Delete Shift:=xlUp
End If
b = 0
a = a + 1
Wend
End Sub
This should do it. It takes input in column A starting in Row 2 until it ends, and ignores more than 2 same consecutive values. Then it copies them in sets and pastes them transposed. If your data is in a different column and row, change the sourceRange variable and the i variable accordingly.
Sub SETranspose()
Application.ScreenUpdating = False
Dim sourceRange As range
Dim copyRange As range
Dim myCell As range
Set sourceRange = range("A2", Cells(Rows.count, 1).End(xlUp))
Dim startCell As range
Set startCell = sourceRange(1, 1)
Dim i As Integer
Dim haveTwo As Boolean
haveTwo = True
For i = 3 To Cells(Rows.count, 1).End(xlUp).Row + 1
If Cells(i, 1).Value = startCell.Value Then
If haveTwo Then
range(startCell, Cells(i, 1)).Copy
startCell.Offset(0, 4).PasteSpecial Transpose:=True
Application.CutCopyMode = False
haveTwo = False
End If
End If
'if the letter changes or end of set, then copy the set over
'If LCase(Left(Cells(i, 1).Value, 1)) <> LCase(startCell.Value) Or _
'i = Cells(Rows.count, 1).End(xlUp).Row + 1 Then
If Len(Cells(i, 1).Value) > 1 Then
Set copyRange = Cells(i, 1)
copyRange.Copy
Cells(startCell.Row, Columns.count).End(xlToLeft).Offset(0, 1).PasteSpecial
Application.CutCopyMode = False
'Set startCell = sourceRange(i - 1, 1)
ElseIf Len(Cells(i, 1).Value) = 1 And Cells(i, 1).Value <> startCell.Value Then
Set startCell = sourceRange(i - 1, 1)
haveTwo = True
End If
Next i
'clear up data
Set sourceRange = Nothing
Set copyRange = Nothing
Set startCell = Nothing
Application.ScreenUpdating = True
End Sub

Resources