Public Sub Rearrange_HasWants()
Dim inputws As Worksheet, outputws As Worksheet
Dim datarange As Range
Dim i As Long, j As Long, Numberofrows As Long, rownum As Long, colnum As Long, ChainStartRow As Long, ChainEndRow As Long
Dim Has As String, Wants As String, Has2 As String, Wants2 As String, EmpID As String, PassedRows As String
Dim done As Boolean
Dim rearrangements As Integer
With Me
Set inputws = .Worksheets("Sheet2")
Set outputws = .Worksheets("Sheet3")
End With
outputws.Cells(2, 1).Resize(20, 30).ClearContents
inputws.Activate
Set datarange = [HasWants]
Maxrows = datarange.Rows.Count
datarange.Offset(, 2).Resize(, 1).ClearContents
' -------------------------------------------------------------------------------------------------------------------
' Start with cell A2
' Initialize i to 1 and Numberofrows to the maximum number of rows
' Each time a row of data is removed , Numberofrows will be decremented by 1
' -------------------------------------------------------------------------------------------------------------------
Columns("A:C").Select
ActiveWorkbook.Worksheets("Sheet2").Sort.SortFields.Clear
ActiveWorkbook.Worksheets("Sheet2").Sort.SortFields.Add Key:=Range("B2:B108") _
, SortOn:=xlSortOnValues, Order:=xlAscending, DataOption:=xlSortNormal
With ActiveWorkbook.Worksheets("Sheet2").Sort
.SetRange Range("A1:C108")
.Header = xlYes
.MatchCase = False
.Orientation = xlTopToBottom
.SortMethod = xlPinYin
.Apply
End With
'sort above
rownum = 2
colnum = 1
i = 1
Numberofrows = Maxrows
Do While ((Numberofrows > 0) And (i <= Maxrows))
With datarange
Has = .Cells(i, 1).Value
Wants = .Cells(i, 2).Value
If Has = vbNullString Then GoTo LoopExit:
' -----------------------------------------------------------------------------------------------------------
' If there is data to be processed ,
' first save the current Has and Wants values in the variables SavedHas and SavedWants
' We maintain a string variable which keeps track of the rows we have passed while trying to find a match
' PassedRows is a string variable which will have the row number preceded and followed by an x ,
' so that there is no accidental match due to two consecutive digits such as 1 and 2 matching row 12
' as well as rows 1 and 2
' -----------------------------------------------------------------------------------------------------------
SavedHas = Has
SavedWants = Wants
If .Cells(i, 3) = 1 Then GoTo LoopExit:
PassedRows = "x" & CStr(i) & "x"
SavedRows = PassedRows
.Cells(i, 3).Value = 1
matchfound = False
Do
Swapped = False
For j = 1 To Maxrows
If .Cells(j, 3) <> 1 Then
CurrHas = .Cells(j, 1).Value
CurrWants = .Cells(j, 2).Value
If Not IsEmpty(CurrHas) Then
CurrRow = "x" & CStr(j) & "x"
If InStr(1, PassedRows, CurrRow) = 0 Then
If CurrHas = Wants And CurrWants = SavedHas Then
matchfound = True
Exit For
End If
If CurrHas = Wants Then
Has = CurrHas
Wants = CurrWants
Swapped = True
PassedRows = PassedRows & CurrRow
Exit For
End If
End If
End If
End If
Next
Loop Until (matchfound Or (Not Swapped))
If matchfound Then
Has = SavedHas
Wants = SavedWants
PassedRows = SavedRows
EmpID = .Offset(, -1).Cells(i, 1).Value
outputws.Cells(rownum, colnum).Value = EmpID & Chr(10) & Has
outputws.Cells(rownum, colnum + 1).Value = EmpID & Chr(10) & Wants
colnum = colnum + 2
.Cells(i, 1).Value = vbNullString
.Cells(i, 2).Value = vbNullString
.Cells(i, 3) = 1
Numberofrows = Numberofrows - 1
Do
Swapped = False
For j = 1 To Maxrows
If .Cells(j, 3) <> 1 Then
CurrHas = .Cells(j, 1).Value
CurrWants = .Cells(j, 2).Value
If Not IsEmpty(CurrHas) Then
CurrRow = "x" & CStr(j) & "x"
If InStr(1, PassedRows, CurrRow) = 0 Then
If CurrHas = Wants And CurrWants = SavedHas Then
EmpID = .Offset(, -1).Cells(j, 1).Value
outputws.Cells(rownum, colnum).Value = EmpID & Chr(10) & CurrHas
outputws.Cells(rownum, colnum + 1).Value = EmpID & Chr(10) & CurrWants
colnum = colnum + 2
.Cells(j, 1).Value = vbNullString
.Cells(j, 2).Value = vbNullString
.Cells(j, 3).Value = 1
Numberofrows = Numberofrows - 1
Swapped = False
Exit For
End If
If CurrHas = Wants Then
Has = CurrHas
Wants = CurrWants
Swapped = True
PassedRows = PassedRows & CurrRow
EmpID = .Offset(, -1).Cells(j, 1).Value
outputws.Cells(rownum, colnum).Value = EmpID & Chr(10) & Has
outputws.Cells(rownum, colnum + 1).Value = EmpID & Chr(10) & Wants
colnum = colnum + 2
.Cells(j, 1).Value = vbNullString
.Cells(j, 2).Value = vbNullString
.Cells(j, 3).Value = 1
Numberofrows = Numberofrows - 1
Exit For
End If
End If
End If
End If
Next
k = k + 1
Loop Until ((Not Swapped) Or (k >= Maxrows))
rownum = rownum + 1
colnum = 1
i = 1
Else '
If Len(PassedRows) > 4 Then
ChainStartRow = Val(Replace(Left(PassedRows, 4), "x", ""))
ChainEndRow = Val(Replace(Right(PassedRows, 4), "x", ""))
.Cells(ChainStartRow, 3).ClearContents
.Cells(ChainEndRow, 3).Value = 1
End If
i = 1
End If
LoopExit:
i = i + 1
End With
Loop
datarange.Offset(, 2).Resize(, 1).ClearContents
end sub