VBA Count maximum occurance of a value in a row [closed] - vba

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 5 years ago.
Improve this question
I need to write a macro that searches a specified column and counts all the cells that contain a specified string, such as character "p" and character "q" then associate this in another column i.e the total column, indicating the character which has occurred maximum number of times in the corresponding row
Have attached a sample screen shot of the same.
Does anyone have any ideas?
Thank you in advance.

Based on your additional criteria of having to exclude certain columns in the row I think it may indeed be easier to use VBA and create a user defined function that you can then enter into the cells in your spreadsheet in the same way as any other function.
I've shown my attempt below which basically checks the column of each cell in the range to ensure it has a header of "Symbol" and if so adds the value of that cell to an Array (after being converted to a number value). There is then another function that gets the mode from that array (this only works on numeric values which is why it was converted in the previous step). Finally that is converted back to a letter.
It's quite a roundabout way and there may be an easier approach but hopefully this will work for now and give you some idea's of how to create these kind of functions for yourself.
Create a new module in your VBA project and copy all 4 of the below procedures into it:
Option Explicit
Public Function MostFrequentValue(RNG As Range) As String
Dim HeaderRow As Integer
Dim a As Range
Dim arr As Variant
HeaderRow = 1 'Change this to whatever row your headers are in
For Each a In RNG.Cells
If Cells(HeaderRow, a.Column) = "Symbol" Then
If IsEmpty(arr) Then
arr = Array(ConvertLetterToNumber(a.Value))
Else
ReDim Preserve arr(UBound(arr) + 1)
arr(UBound(arr)) = ConvertLetterToNumber(a.Value)
End If
End If
Next
MostFrequentValue = ConvertNumberToLetter(ArrayMode(arr))
End Function
.
Function ConvertNumberToLetter(ByVal strSource As Integer) As String
ConvertNumberToLetter = LCase(Chr(strSource + 64))
End Function
.
Function ConvertLetterToNumber(ByVal strSource As String) As Integer
Dim i As Integer
Dim strResult As String
strSource = UCase(strSource)
For i = 1 To Len(strSource)
Select Case Asc(Mid(strSource, i, 1))
Case 65 To 90:
strResult = strResult & Asc(Mid(strSource, i, 1)) - 64
Case Else
strResult = strResult & Mid(strSource, i, 1)
End Select
Next
ConvertLetterToNumber = strResult
End Function
.
Function ArrayMode(Ray As Variant) As Integer
With Application
ArrayMode = .Mode(Ray)
End With
End Function
You would then enter the function into a cell like so =MostFrequentValue("A2:C2")
P.S. This assumes that the symbol in each value in the Symbol column is a lowercase letter of the alphabet (a-z). This appears to be the case from your example

You don't need a macro. The below formula will give you what you need. The range being counted appears in the formula 3 times. You would need to adjust this for the range you want to check
=INDEX(A1:C1,MODE(MATCH(A1:C1,A1:C1,0)))
Note: this will return an error if no single character appears more times than any other. In this case you could wrap the above formula in an IFERROR function to return whatever value you would want to see when this happens.
If you have any blank cells in the row, you can use the following array formula, which adds an IF statement to test for empty cells:
=INDEX(A1:C1,MODE(IF(A1:C1<>"",MATCH(A1:C1,A1:C1,0))))
When entering this formula you will need to press Ctrl + Shift + Enter

Related

Indexing through an array by column number

I've looked up info with regards to column attributes. I'm trying to perform some insertions and copying of information within an array. The crux of my issue is that I want o nest some actions within a loop, so I need to index the column by a number not letter.
The first thing I do is find a starting point based upon a header name:
Dim EnvCondCol As String
Dim EnvCondColN As Long
Dim lColVVS As Integer
lColVVS = VET_VS.UsedRange.Columns.Count ' finds last column
For n = 1 To lColVVS
If UCase(VET_VS.Cells(3, n).Value) Like "*ENVIRONMENTAL CONDITION*" Then ' All Caps when using "like"
EnvCondCol = Split(VET_VS.Cells(3, n).Address, "$")(1)
EnvCondColN = Range(EnvCondCol & 1).Column
Exit For
End If
Next n
This works and when I watch EnvCondCol and EnvCondColN is can see EnvCondCol = "I" and EnvCondColN = "9"
Eventually, I want to insert a new column, and this line generates a syntax error:
VET_VS.Range(Columns.(EnvCondColN)).EntireColumn.Insert
When I watch EnvCondColN, it is a number, and I have tried changing the dim to other types, such as integer
Also elsewhere, I want to copy information from a cell into another cell from within a loop. This generates a syntax error.
VET_VS.Range(Columns.(EnvCondColN + i)).Copy VET_VS.Range(Columns.(EnvCondColN + j))
If I replace EnvCondColN with a value like 5, then this works. Example: VET_VS.Range(Columns.(5)).EntireColumn.Insert
Why isn't the variable working as a column reference??
Thank you all for looking!
change
VET_VS.Range(Columns.(EnvCondColN)).EntireColumn.Insert
to
VET_VS.Columns(EnvCondColN).EntireColumn.Insert

Round off 4.54545454545455 to an integer [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 7 years ago.
Improve this question
I have a to sum the values which are adjacent to "Leave" valued cell.These values are like 4.54545454545455 and on.
Since "leave" comes intermittently I use condition and accordingly store values from adjacent cell in redefined Integer array(Redim based on the number of occurrences of "Leave". Now I am summing that array here lies the problem as sum is coming up something like 13.409091E-02 and only ULong(which does not work in my VBA editor) can store values like this as much I researched and know. So, Datatypes like Long, Double are not able to store such a value.Which is giving a sum not asked. Is there any way this could work or Is there any other way such that I can check intermittent adjacent values to"Leave"and sum them.
Dim leavearray() As Long <br/>dim xsum as long<br/>dim counter3 as Integer<br/>dim colum as Integer<br/>dim ro as Integer<br/>dim ctr as Integer<br/>dim change as Integer
For counter3 = colum To ro<br/>
If Cells(counter3, 29) = "Leave" Then<br/>
ctr = ctr + 1<br/>
ReDim leavearray(ctr - 1)<br/>
Else<br/>
End If<br/>
Next counter3<br/><br/>For counter = colum To ro<br/>
If Cells(counter, 29) = "Leave" Then<br/>
change = change + 1<br/>
leavearray(change - 1) = Cells(counter, 30).Value 'stores value like 3.409091E-02 in array as and when "leave" occurs in its adjacent cell.<br/>
Else<br/>
End If<br/>
If counter = ro Then<br/>
xsum = WorksheetFunction.Sum(leavearray)'It Stores 0 where the problem lies.
If you have a number and wants only the integer part of it, you should use the command Int(), if you want it to be rounded, use CInt(), as shown in the code below:
Dim integerResult As Integer
Dim singleVariable As Single
singleVariable = 4.65
integerResult = Int(singleVariable)
MsgBox (integerResult)
integerResult = CInt(singleVariable)
MsgBox (integerResult)
The first MessageBox will show you 4, and the second MessageBox will show you 5.

Extract 5-digit number from one column to another

I need help with extracting 5-digit numbers only from one column to another in Excel 2010. These numbers can be in any position of the string (beginning of the string, anywhere in the middle, or at the end). They can be within brackets or quotes like:
(15478) or "15478" or '15478' or [15478]
I need to ignore any numbers that are less than 5 digits and include numbers that start with 1 or more leading zeros (like 00052, 00278, etc.) and ensure that leading zeros are copied over to the next column. Could someone help me with either creating a formula or UDF?
Here is a formula-based alternative that will extract the first 5 digit number found in cell A1. I tend to prefer reasonably simple formula solutions over VBA in most situations as formulas are more portable. This formula is an array formula and thus must be entered with Ctrl+Shift+Enter. The idea is to split the string up into every possible 5 character chunk and test each one and return the first match.
=MID(A1,MIN(IF(NOT(ISERROR(("1"&MID(A1,ROW(INDIRECT("R1C[1]:R"&(LEN(A1)-4)&"C[1]",FALSE)),5)&".1")*1))*ISERROR(MID(A1,ROW(INDIRECT("R1C[1]:R"&(LEN(A1)-4)&"C[1]",FALSE))+5,1)*1)*ISERROR(MID(A1,ROW(INDIRECT("R1C[1]:R"&(LEN(A1)-4)&"C[1]",FALSE))-1,1)*1),ROW(INDIRECT("R1C[1]:R"&(LEN(A1)-4)&"C[1]",FALSE)),9999999999)),5)
Let's break this down. First we have an expression I used twice to return an array of numbers from 1 up to 4 less than the length of your initial text. So if you have a string of length 10 the following will return {1,2,3,4,5,6}. Hereafter the below formula will be referred to as rowlist. I used R1C1 notation to avoid potential circular references.
ROW(INDIRECT("R1C[1]:R"&(LEN(A1)-4)&"C[1]",FALSE))
Next we will use that array to split the text into an array of 5 letter chunks and test each chunk. The test being performed is to prepend a "1" and append ".1" then verify the chunk is numeric. The prepend and append eliminate the possibility of white space or decimals. We can then check the character before and the character after to make sure they are not numbers. Hereafter the below formula will be referred to as isnumarray.
NOT(ISERROR(("1"&MID(A1,rowlist,5)&".1")*1))
*ISERROR(MID(A1,rowlist+5,1)*1)
*ISERROR(MID(A1,rowlist-1,1)*1)
Next we need to find the first valid 5 digit number in the string by returning the current index from a duplicate of the rowlist formula and returning a large number for non-matches. Then we can use the MIN function to grab that first match. Hereafter the below will be referred to as minindex.
MIN(IF(isnumarray,rowlist,9999999999))
Finally we need to grab the numeric string that started at the index returned by the MIN function.
MID(A1,minindex,5)
The following UDF will return the first five digit number in the string, including any leading zero's. If you need to detect if there is more than one five digit number, the modifications are trivial. It will return a #VALUE! error if there are no five-digit numbers.
Option Explicit
Function FiveDigit(S As String, Optional index As Long = 0) As String
Dim RE As Object
Set RE = CreateObject("vbscript.regexp")
With RE
.Pattern = "(?:\b|\D)(\d{5})(?:\b|\D)"
.Global = True
FiveDigit = .Execute(S)(index).submatches(0)
End With
End Function
As you may see from the discussion between Mark and myself, some of your specifications are unclear. But if you would want to exclude decimal numbers, when the decimal portion has five digits, then the regex pattern in my code above should be changed:
.Pattern = "(?:\d+\.\d+)|(?:\b|\D)(\d{5})(?:\b|\D)"
I just wrote this UDF for you , basic but will do it...
It will find the first 5 consecutive numbers in a string, very crude error checking so it just says Error if anything isn't right
Public Function GET5DIGITS(value As String) As String
Dim sResult As String
Dim iLen As Integer
sResult = ""
iLen = 0
For i = 1 To Len(value)
If IsNumeric(Mid(value, i, 1)) Then
sResult = sResult & Mid(value, i, 1)
iLen = iLen + 1
Else
sResult = ""
iLen = 0
End If
If iLen = 5 Then Exit For
Next
If iLen = 5 Then
GET5DIGITS = Format(sResult, "00000")
Else
GET5DIGITS = "Error"
End If
End Function

VBA to return nth row number from a filtered table in excel [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 7 years ago.
Improve this question
Can anyone please help me with finding the absolute row number of nth element after filter is applied in an excel table.
For example, I have filter on and have a visible range of data element. Now 20th (nth) row in this filtered range could be 60th row (absolute sense) when no filters are on. Is there a way to find the absolute row number using VBA?
Simplest method is special cells. See below:
Sub test()
Dim i As Integer, j As Integer, k As Integer
Dim Report As Worksheet
Set Report = Excel.ActiveSheet ' Store the current worksheet in a variable (always a good idea)
Dim visRng As Range ' Creating a range variable to store our table, excluding any rows that are filtered out.
Set visRng = Report.UsedRange.SpecialCells(xlCellTypeVisible) ' Select only rows within the used range that are visible.
Dim r As Range
For Each r In visRng.Rows ' Loop through each row in our visible range ...
MsgBox (r.Row) ' ... and retrieve the "absolute" row number.
Next
End Sub
EDIT
Tom claims this method will not work, but I'm pretty sure it does what you ask. Example:
Here is my original test table--unfiltered so you can see what we're doing.
And then we filter a couple values somewhere in the middle of the table...
Now when we run the script I posted above, our message box will show the "absolute" row number for each unfiltered row. Results are 1,3,4,5, and 7.
As a function I suggest
Function RowNum(Target As Range) As Long
RowNum = Target.Row
End Function
use by entering in a cell =RowNum(E9). If you want the line relative to the table start and your table starts in -say- row 21, just subtract this from the result (you can use the same function to find the row of table start or course) ... e.g. =rownum(A2)-rownum($A$1) ... mind the absolute notation of table header!
If you don't like this as a function, you could use the SelectionChange event to display the row number of the selected cell in the message line (optionally depending on a "debug flag" somewhere in your sheet).
Tne non-VBA approach would be to use the CELL formula ... e.g. =CELL("row",A1)
The answer brought up by #Lopsided wont work, if there are other hidden cells after the nth entry. They would then be added to the absolute position.
This'll work, you have to change n by yourself in the script. Changing that shouldn't be to hard. If you have any questions regarding that, feel free to ask. (;
Sub absoluteRowID()
Dim RowCount, hiddenRows As Integer
'relative position n
n = 5
i = 0
Do While i < n
i = i + 1
If ThisWorkbook.Sheets(1).Rows(i).EntireRow.Hidden Then
'if there is a hidden row, position is incremented
n = n + 1
End If
'if there is no hidden row, nothing happens
Loop
MsgBox (i)
End Sub
HTH

VBA: preceding zeros dropped when copied over

I am creating a copy of an Excel file using VBA. In the file, there is a column that includes numbers with preceding zeros. The copy of the file is created, but the data in this column is dropped. I need to keep the values with the preceding zeros. How can I resolve this problem with VBA?
The best way is to pre-format the column as Text by setting Range.NumberFormat to "#". This way, if a user edits the cell, the cell will stay as text and maintain it's leading zeros. Here is a VBA example:
ActiveSheet.Range("C:C").NumberFormat = "#"
Convert each cell in that column to a text field prior to exporting it. That should ensure that every character is retained (and not treated like a number, which is what it sounds like is happening).
An additional possibility is to append an apostrphe to each cell. This will treat all the values as text which is useful when different tabs treat common values as text vs number (ie copied in vs calculated).
This is done by using the Chr() function and assigning it the character code 39('):
For x = 1 to 100
If Sheets(origSheet).Cells(x, "A").Value <> "" Then
Sheets(origSheet).Cells(x, "A").Value = Chr(39) & Sheets(origSheet).Cells(x, "A").Value
End If
Given the accepted answer, it's probably not what you need, but setting a custom number format will also get the preceeding zeroes back into the displayed value.
To show a value with leading zeroes up to 8 digits, for example, set the format to 00000000, then 123 will be displayed as 00000123.
Both the method here and the format-as-text method will result in cell values that will still work in calculations, although horizontal alignment will be different by default. Note also that, for example, concatenating strings to the values will result in differences:
as text: displays 00000123, append "x" to get 00000123x
as number with custom format: displays 00000123, append "x" to get 123x, because it's still really a number.
Probably TMI, though!
This is the code I have created to resolve this issue:
Public Sub Change_10_Digit()
'----------------------------------------------------------------------------
' Change numeric loan number ot a 10 digit text number
' 2010-05-21 by Jamie Coxe
'
' Note: Insure exracted data Column is formated as text before running macro
'----------------------------------------------------------------------------
Dim Lastrow As Long
Dim StartRow As Long
Dim Col As String
Dim RowNum As Long
Dim nCol As String
Dim Loan As String
Dim Digit_Loan As String
Dim MyCell As String
Dim NewCell As String
Dim Cell_Len As Long
Dim MyOption As Long
'----- Set Options -------------------------------------------------------
MyOption = 2 '1 = place data in new column, 2 = Replace data in cell
StartRow = 2 'Start processing data at this row (skip header row)
Col = "B" 'Loan number in this colmun to be changed to 10 digit
nCol = "G" 'New column to place value (option 1 only)
'----- End Option Setings ------------------------------------------------
'Get last row
Lastrow = Range(Col & "65536").End(xlUp).Row
For RowNum = StartRow To Lastrow
'Combined Column and Row number to get cell data
MyCell = Col & RowNum
'Get data in cell
Loan = Range(MyCell).Value
'Change data in cell to 10 digit numeric with leading zeros
Digit_Loan = Format(Loan, "0000000000")
If My0ption = 1 Then
'Option 1 enter value in new cell
NewCell = nCol & RowNum
Range(NewCell).Value = Digit_Loan
Else
'Option 2 replace value in cell
Range(MyCell).Value = Digit_Loan
End If
Next RowNum
End Sub