Reputation: 1726
I want to select M
companies from a sample of S
companies and doing this starting from a random number selected between 1
and S
and selecting every N
th company.
To get the sample of M, I want the loop to come back to starting point for selecting the companies. Here xInterval
is N
, lrowCount
is S
and M
is N/S
. I tried using offset and changing indices of for loop.
Can anyone suggest a solution?
Sub circularSystematicSampling()
Dim rng As Range
Dim InputRng As Range
Dim OutRng As Range
Dim xInterval As Integer
Dim lrowCount As Integer
Dim endPoint As Integer
Dim circular As Boolean
xTitleId = "Testing"
Set InputRng = ActiveSheet.UsedRange
Set InputRng = InputRng.Offset(1).Resize(InputRng.Rows.Count - 1)
InputRng.Select
xInterval = Application.InputBox("Number of companies is" & " " & InputRng.Rows.Count & vbCrLf & " Enter row interval", xTitleId, Type:=1)
lrowCount = ActiveSheet.UsedRange.Rows.Count
randomStart = Int((lrowCount - 1 + 1) * Rnd + 1)
endPoint = Int(lrowCount + randomStart)
endPoint2 = Int(randomStart - 1)
If endPoint > lrowCount Then
circular = True
End If
For i = (1 + randomStart) To endPoint Step xInterval
Set rng = InputRng.Cells(i, 1)
If circular Then
ActiveCell.Offset(1, 0).Select
End If
If OutRng Is Nothing Then
Set OutRng = rng
Else
Set OutRng = Application.Union(OutRng, rng)
End If
Next
OutRng.EntireRow.Select
With Selection.Interior
.PatternColorIndex = xlAutomatic
.Color = 65535
.TintAndShade = 0
.PatternTintAndShade = 0
End With
End Sub
How do I modify this loop to come back to starting point when selecting xInterval row? Thanks.
Edit: Another approach while circular true
If circular Then
For j = 1 To endPoint2 Step xInterval ' ActiveCell.Offset(1, 0).Select
Set rng2 = InputRng.Cells(j, endPoint2)
End If
If OutRng Is Nothing Then
Set OutRng = rng
Else
Set OutRng = Application.Union(OutRng, rng, rng2)
End If
Another possibility using DO while
For i = (1 + randomStart) To endPoint Step xInterval
Do While Not IsEmpty(ActiveCell)
Set rng = InputRng.Cells(i, endPoint)
Do While IsEmpty(ActiveCell)
ActiveCell.Offset(1, 0).Select
For j = 1 To endPoint2 Step xInterval
Set rng2 = InputRng.Cells(j, endPoint2)
End If
If OutRng Is Nothing Then
Set OutRng = rng
Else
Set OutRng = Application.Union(OutRng, rng, rng2)
End If
Upvotes: 1
Views: 172
Reputation: 19289
If you just loop over the actual rows from 1
to S
then you can use the Mod
function to send the loop back 'to the top':
For lngCounter = 1 To lngRowCount Step lngRowInterval
lngTargetRow = (lngRandRowStart + lngCounter) Mod lngRowCount
strOutRanges = strOutRanges & rngData.Cells(lngTargetRow + 1, 1).Address & ","
Next lngCounter
I had an issue with your method of Union
ing the Range
s so am just building a list of cell addresses to format in the loop.
Full example:
Option Explicit
Sub circularSystematicSampling()
Dim rngData As Range
Dim lngRowCount As Long
Dim lngRowInterval As Long
Dim lngRandRowStart As Long
Dim lngCounter As Long
Dim lngTargetRow As Long
Dim strOutRanges As String
Dim rngOut As Range
' set range to iterate
Set rngData = ThisWorkbook.Worksheets("Sheet1").UsedRange
' drop header
Set rngData = rngData.Offset(1).Resize(rngData.Rows.Count - 1)
' get total rows
lngRowCount = rngData.Rows.Count
' set an interval
lngRowInterval = Application.InputBox("Enter row interval", "Test", 1)
' set a random start point
lngRandRowStart = Int(rngData.Rows.Count * Rnd + 1)
' iterate rows - calculate offset in loop
strOutRanges = ""
For lngCounter = 1 To lngRowCount Step lngRowInterval
lngTargetRow = (lngRandRowStart + lngCounter) Mod lngRowCount
strOutRanges = strOutRanges & rngData.Cells(lngTargetRow + 1, 1).Address & ","
Next lngCounter
'drop trailing comma
strOutRanges = Left(strOutRanges, Len(strOutRanges) - 1)
' create range with string of addresses
Set rngOut = Range(strOutRanges)
Debug.Print rngOut.Address
With rngOut.EntireRow.Interior
.PatternColorIndex = xlAutomatic
.Color = 65535
.TintAndShade = 0
.PatternTintAndShade = 0
End With
End Sub
Upvotes: 1