0

I'm trying to speed up a process where a macro checks a range of text in column B to group them in column C as a specific keyword. For example, if B2 has apple, it marks it as fruit in C2, if B3 has Onion, it marks it as vegetables in C3. Eventually some other texts I would like for them to just appear as "other". Unfortunately, I am not having any luck in actually making it work as I wish.

Sub Categorize()

If Range("B2:B100").text="Apple" then
Range("C2:C100").text="Fruit"

ElseIf Range("B2:B100").text="Banana" Then
Range("C2:C100").text="Fruit"

ElseIf Range("B2:B100").text="Onion" Then
Range("C2:C100").text="Vegetable"

Else
Range("C2:C100")="Other"

End If
End Sub

Can you guys help me out?

2
  • Welcome to StackOverflow! Please edit the question to include the actual behavior of your code - until we know what it's doing wrong, it's hard to guess what might make it right. Commented Oct 1, 2019 at 23:00
  • If you care speed, you should use Excel Formula. Commented Oct 2, 2019 at 2:35

3 Answers 3

3

This should do what you want. Keep an eye out for caps issues, or just force everything to be upper/lower case.

Sub Categorize()
Dim aCell As Range
Const theColumnToWriteTo As Long = 4 'column d    

For Each aCell In Range("b2:b100").Cells


If aCell.Value2 = "Apple" Then

    aCell.Worksheet.Cells(aCell.Row, theColumnToWriteTo).Value = "Fruit"

ElseIf aCell.Value2 = "Banana" Then
    aCell.Worksheet.Cells(aCell.Row, theColumnToWriteTo).Value = "Fruit"

ElseIf aCell.Value2 = "Onion" Then
    aCell.Worksheet.Cells(aCell.Row, theColumnToWriteTo).Value = "Vegetable"

Else
    aCell.Worksheet.Cells(aCell.Row, theColumnToWriteTo).Value = "other"

End If

Next aCell

End Sub

UPDATE Here's an alternative approach that is more complex, but is FAR more efficient and really is the "correct" way to do such actions. The result is that your worksheet is only modified once, which can make a huge difference when doing thousands of cells in a worksheet with formulas everywhere.

You can change the Const parameters.

Sub getArays()
Const pullRangeAddress As String = "B2:B100"
Const destinationAddress As String = "C2"
Dim WS As Worksheet: Set WS = ActiveSheet ' of whatever sheet



    Dim tRay(): tRay() = WS.Range(pullRangeAddress).Value2

    'create new blank array to hold values
    ReDim nRay(LBound(tRay, 1) To UBound(tRay, 1), LBound(tRay, 2) To UBound(tRay, 2))


    Dim x As Long, y As Long
    For x = LBound(tRay, 1) To UBound(tRay, 1)
        For y = LBound(tRay, 2) To UBound(tRay, 2)

            If tRay(x, y) = "Banana" Then
                nRay(x, y) = "Fruit"

            ElseIf tRay(x, y) = "Apple" Then
                nRay(x, y) = "Fruit"

            ElseIf tRay(x, y) = "Onion" Then
                nRay(x, y) = "Vegetable"

            Else
                nRay(x, y) = "Other"

            End If
        Next y
    Next x


    WS.Range(destinationAddress).Resize(UBound(nRay, 1), UBound(nRay, 2)) = nRay

End Sub

Updated Again Trying To Keep Everyone In The Comments Happy

You could use a select statement which is a little easier to visualize.

For x = LBound(tRay, 1) To UBound(tRay, 1)

For y = LBound(tRay, 2) To UBound(tRay, 2)

Select Case tRay(x, y)

    Case "Banana", "Apple", "Grapes"
        nRay(x, y) = "Fruit"

    Case "Onion"
        nRay(x, y) = "Vegetable"

    Case "Mushrooms", "Weed"
        nRay(x, y) = "illegal"

    Case Else
        nRay(x, y) = "Other"

    End Select
Next y
Next x

Adding Another Option That Leverages Excel's new IFS function... Different answer had a good idea of just using a formula. I like the concept, but no helper column allowed!

Range("D2:D200").FormulaR1C1 _
"=IFS(OR(RC[-1]=""Apple"",RC[-1]=""Banana""),""Fruit"",RC[-1]=""Onion"",""Vegetable"",TRUE,""Other"")"
Sign up to request clarification or add additional context in comments.

9 Comments

@watapana as I said, I misread your question the first time, but the newer code from about 9 minutes ago should work.
I am receiving run-time '1004' at the ElseIf aCell.Value2 = "banana" Then aCell.Worksheet.Cells(aCell.Row, theColumnToWriteTo).Value = "Vegetable"
Not sure why. It works fine on mine. Feel free to download and review: 1drv.ms/x/s!AiO7_3PtXmZ9goIy5hzGBf95yqJFEg?e=r0hxfj
May improve this using a Select Case switch instead of If/ElseIf/.../Else, just my $0.02, but otherwise this looks good.
@DavidZemens at one point I ran a massive test comparing the two methods. Over the course of several million iterations, elseif performed a millisecond faster which should be translated to mean "makes no difference to a normal person"... so I updated the answer. Good call.
|
1

If you care about speed, use Excel Formula. enter image description here

If you want to use VBA, you could use FormulaR1C1 property of Range object.

Range("D2:D200").FormulaR1C1 = "=iferror(vlookup(rc2,c7:c8,2,false),""other"")"

enter image description here

2 Comments

Technically this will not always return the same result of the macro as yours is case insensitive, which is actually probably what OP wanted. However, cheater column is no bueno! I'm going to call the police.... just kidding. Nice answer I gave you a 👍🏼
=IF(OR(EXACT(RC[-1],"Apple"),EXACT(RC[-1],"Banana")),"Fruit",IF(EXACT(RC[-1],"Onion"),"Vegetable","Other")) for case insensative.
0
Sub UpdateScale()
Dim ChartVar As Chart
Dim lMax As Long, lMin As Long

On Error GoTo ScalingProblem
    'Assigns the values in the Min and Max ranges to variables.
    With Ëèñò9
    ' Sheet9
        lMax = .Range("Max").Value
        lMin = .Range("Min").Value
        'Creates chart object.
        Set ChartVar = .ChartObjects("Chart 1").Chart
        
               With ChartVar.Axes(xlValue, xlPrimary)  'Adjusts the price axis
                   .MinimumScale = 1.301    'iMin
                   .MaximumScale = 1.326    'iMax
               End With
            
    End With
Exit Sub

ScalingProblem:
'RetrievalProblem:
'    MsgBox "Unable to update chart scale.", vbCritical + vbOKOnly, "Scaling Error"
End Sub

1 Comment

how to solve the problem of automatically determining the maximum and minimum

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.