I have an excel file written in this way:
187712 201 37 0.18
2525 580 149 0.25
136829 137 43 0.31
I need to export this file with same spaces, same formatting in a txt file. How can i do it? I've tryied Save As | Formatted Text (Space Delimited) (*.prn) but not working because i have an issue on the last column. Is there a macro? Thanks.
EDIT: i tryied a macro:
Sub TEST()
Dim c As Range, r As Range
Dim output As String
For Each r In Range("A1:L504").Rows
For Each c In r.Cells
output = output & " " & c.Value
Next c
output = output & vbNewLine
Next r
Open "D:\MyPath\text.txt" For Output As #1
Print #1, output
Close
End Sub
but the result is
187712 201 37 0.18
2525 580 149 0.25
136829 137 43 0.31
These values are only an example because there are about 504 columns!! Anyway the problem is that if in the first column there is a value shorter then the others it lost the formatting like the second row as you can see.
Your posted data shows fixed fields with field-widths of 8,7,7,4 (each field is a combination of characters and trailing blanks). These can be adjusted as necessary in the macro below. Also adjust the folder name to suit your needs:
Sub FixedField()
Dim fld(1 To 4) As Long
Dim V(1 To 4) As String
Dim N As Long, L As Long
Dim K As Long
fld(1) = 8
fld(2) = 7
fld(3) = 7
fld(4) = 4
N = Cells(Rows.Count, "A").End(xlUp).Row
Close #1
Open "c:\TestFolder\test.txt" For Output As #1
For L = 1 To N
outpt = ""
For K = 1 To 4
V(K) = Cells(L, K).Text
While Len(V(K)) <> fld(K)
V(K) = V(K) & " "
Wend
outpt = outpt & V(K)
Next K
MsgBox outpt
Print #1, outpt
Next L
Close #1
End Sub
It is also assumed that the data starts in column A.
I struggled with that also numerous times, the only way I found was with a VBA function I created (the tricky part is determining the "widest" column for plain-text layout). Fair warning: I didn't build a lot "smarts" into this, the output can be a little quirky.
Usage:
Select the cells you want formatted to plain-text, then run the macro (I have the macro assigned to a button, I use it all the time!). If the top row is center-aligned, then let's /assume/ it's a header. And watch for right-aligned columns, and output those right-aligned.
The marco will copy the desired output to the clip-board, then paste the result in Notepad (or similar) to do with as desired.
Example output (I threw in some headers)
CustId Views Selected Cost
187712 201 37 0.18
2525 580 149 0.25
136829 137 43 0.31
The code:
Sub FormatSelectionToPlainText()
' ---------------------------------------------------------------------------
' Author: Jay R. Ohman
' Ohman Automation Corp., http://www.OhmanCorp.com
' ** disclaimer and release: I am NOT an expert **
' ** programmer, use my coding at your own risk! **
' ---------------------------------------------------------------------------
Dim rFound As Range, RngCol1 As Integer, RngRow1 As Integer, ActCol As Integer, ActRow As Integer, x As Integer
Dim MaxCellLen() As Variant, CellAlignRight() As Variant, HdrLen() As Variant, xDbg As Boolean, xVal As Variant
Dim SepSpace As Integer, RetStr As String, RetLen As Integer, MsgStr As String, HasHdr As Boolean
Dim GeneralIsRightAlignedFactor As Single, TotalRows As Integer
Dim oClip As DataObject
xDbg = True ' output stuff to the immediate window?
GeneralIsRightAlignedFactor = 0.75 ' threshhold for deeming a column as right-aligned
Set oClip = New DataObject
MsgStr = "(looking for top row to be center aligned as header)"
If MsgBox("Are the cells to be copied selected?" & vbCrLf & MsgStr, vbYesNo + vbQuestion, "Auto-Fill Time Slots") = vbYes Then
If (Selection Is Nothing) Then
MsgBox "Nothing Selected."
Else
SepSpace = 2 ' number of spaces between columns
RetLen = 0
HasHdr = True
Set rFound = Selection
RngCol1 = rFound.Column
RngRow1 = rFound.Row
Debug.Print Selection.Columns.Count
ReDim Preserve MaxCellLen(Selection.Columns.Count) ' max cell length
ReDim Preserve CellAlignRight(Selection.Columns.Count) ' track the cell alignment
ReDim Preserve HdrLen(Selection.Columns.Count) ' header row max cell length
For ActCol = RngCol1 To RngCol1 + Selection.Columns.Count - 1
x = (ActCol - RngCol1 + 1)
' If xDbg Then Debug.Print Cells(RngRow1, ActCol).HorizontalAlignment
If (Cells(RngRow1, ActCol).HorizontalAlignment <> xlCenter) And (Cells(RngRow1, ActCol).Value <> "") Then HasHdr = False
HdrLen(x) = IIf(HasHdr, Len(Cells(RngRow1, ActCol).Value), 0)
MaxCellLen(x) = 0
CellAlignRight(x) = 0
Next
If xDbg Then Debug.Print "HasHdr: " & HasHdr
TotalRows = (RngRow1 + Selection.Rows.Count) - (RngRow1 + IIf(HasHdr, 1, 0))
For ActCol = RngCol1 To RngCol1 + Selection.Columns.Count - 1 ' go find the longest text in each column
x = (ActCol - RngCol1 + 1)
xVal = IIf(HasHdr, 1, 0)
For ActRow = RngRow1 + xVal To RngRow1 + Selection.Rows.Count - 1
' If xDbg Then Debug.Print Cells(ActRow, ActCol).HorizontalAlignment
xVal = Cells(ActRow, ActCol).Value
If (MaxCellLen(x) < Len(Cells(ActRow, ActCol).Value)) Then MaxCellLen(x) = Len(xVal)
If (Cells(ActRow, ActCol).HorizontalAlignment = xlRight) Or _
((Cells(ActRow, ActCol).HorizontalAlignment = xlGeneral) And (IsDate(xVal) Or IsNumeric(xVal))) Then _
CellAlignRight(x) = CellAlignRight(x) + 1
Next
If xDbg Then Debug.Print "Max Length for Column " & ActCol & ": " & MaxCellLen(x) & _
", CellAlignRight.Count: " & CellAlignRight(x) & "/" & TotalRows
RetLen = RetLen + MaxCellLen(x) + SepSpace
Next
RetLen = RetLen - SepSpace ' subtract that last separator space
If HasHdr Then
For ActCol = RngCol1 To RngCol1 + Selection.Columns.Count - 1
x = (ActCol - RngCol1 + 1)
If (HdrLen(x) > MaxCellLen(x)) Then MaxCellLen(x) = HdrLen(x)
Next
End If
RetStr = "" ' build the output text
For ActRow = RngRow1 To RngRow1 + Selection.Rows.Count - 1
For ActCol = RngCol1 To RngCol1 + Selection.Columns.Count - 1
x = (ActCol - RngCol1 + 1)
MsgStr = Cells(ActRow, ActCol).Value ' re-use string variable
' format for right-aligned
If (CellAlignRight(x) / TotalRows >= GeneralIsRightAlignedFactor) And (Not (HasHdr And (ActRow = 1))) Or (Cells(ActRow, ActCol).HorizontalAlignment = xlRight) Then ' aligned right
RetStr = RetStr & Space(MaxCellLen(x) - Len(MsgStr)) & MsgStr
ElseIf (Cells(ActRow, ActCol).HorizontalAlignment = xlCenter) Then
xVal = Fix((MaxCellLen(x) - Len(MsgStr)) / 2)
RetStr = RetStr & Space(xVal) & MsgStr & Space(MaxCellLen(x) - Len(MsgStr) - xVal)
Else
RetStr = RetStr & MsgStr & Space(MaxCellLen(x) - Len(MsgStr))
End If
If ((ActCol - RngCol1) + 1 < UBound(MaxCellLen)) Then RetStr = RetStr & Space(SepSpace)
Next
RetStr = RetStr & vbCrLf
Next
oClip.SetText RetStr
oClip.PutInClipboard
MsgBox ("The selection has been copied to clipboard." & vbCrLf & "Max line length: " & RetLen)
End If
Else
MsgBox ("Have a nice day. :)")
End If
End Sub
Related
I want to tag specified lines of a table for sample review.
Due to the volume of data, running repeated loops over the entire population would result in unacceptably long runtimes (as I have to tag specified sub-populations for QA sampling).
The approach I have taken is to bring in the table, and then filter based on the population I want to sample (for example, filter by location, by product, and by analyst) and then select a percentage of that population for sampling by putting "Sample" into a column.
I have tried several permutations of the code.
The first, where I used the Areas function, threw 1004 errors if there was more than one row.
The second gives strange row selections, including selecting non-hidden rows (and I can't understand why it is picking the rows that it is, as they don't seem to be correctly offset even if it was going by "all rows" not just visible rows).
ActiveSheet.ListObjects("SourceDataTable").Range.AutoFilter Field:=1, Criteria1:="Product1"
sectionCount = ActiveSheet.ListObjects("SourceDataTable").AutoFilter.Range.Columns(1).SpecialCells(xlCellTypeVisible).Cells.Count - 1
If sectionCount = 0 Then sectionSampleSize = 0 Else sectionSampleSize = Int((sectionCount / 10) + 0.5)
MsgBox ("Analyst " & analystLoopCellRef.Value & " ecomm section count is " & sectionCount & " and sample size is " & sectionSampleSize)
Do While sectionSampleSize > 0
sectionLoopRand = Int(sectionCount * Rnd + 1)
MsgBox (sectionLoopRand)
' MsgBox (ActiveSheet.ListObjects("SourceDataTable").DataBodyRange.SpecialCells(xlCellTypeVisible).Areas(1).Columns(40).Rows(sectionLoopRand).Cells(1, 1).Value)
If ActiveSheet.ListObjects("SourceDataTable").DataBodyRange.SpecialCells(xlCellTypeVisible).Columns(40).Rows(sectionLoopRand).Cells(1, 1).Value = "Sample" Then
MsgBox ("Sample overlap")
Else
ActiveSheet.ListObjects("SourceDataTable").DataBodyRange.SpecialCells(xlCellTypeVisible).Columns(40).Rows(sectionLoopRand).Cells(1, 1).Value = "Sample"
' MsgBox ("Sample address is " & ActiveSheet.ListObjects("SourceDataTable").DataBodyRange.SpecialCells(xlCellTypeVisible).Columns(40).Rows(sectionLoopRand).Cells(1, 1).Address)
sectionSampleSize = sectionSampleSize - 1
' MsgBox ("Sample selected")
End If
Loop
Older version
ActiveSheet.ListObjects("SourceDataTable").Range.AutoFilter Field:=1, Criteria1:="Product1"
sectionCount = ActiveSheet.ListObjects("SourceDataTable").AutoFilter.Range.Columns(1).SpecialCells(xlCellTypeVisible).Cells.Count - 1
If sectionCount = 0 Then sectionSampleSize = 0 Else sectionSampleSize = Int((sectionCount / 10) + 0.5)
MsgBox ("Analyst " & analystLoopCellRef.Value & " ecomm section count is " & sectionCount & " and sample size is " & sectionSampleSize)
Do While sectionSampleSize > 0
sectionLoopRand = Int(sectionCount * Rnd + 1)
MsgBox (sectionLoopRand)
' MsgBox (ActiveSheet.ListObjects("SourceDataTable").DataBodyRange.SpecialCells(xlCellTypeVisible).Areas(sectionLoopRand).Columns(40).Cells(1, 1).Value)
If ActiveSheet.ListObjects("SourceDataTable").DataBodyRange.SpecialCells(xlCellTypeVisible).Areas(sectionLoopRand).Columns(40).Cells(1, 1).Value = "Sample" Then
MsgBox ("Sample overlap")
Else
ActiveSheet.ListObjects("SourceDataTable").DataBodyRange.SpecialCells(xlCellTypeVisible).Areas(sectionLoopRand).Columns(40).Cells(1, 1).Value = "Sample"
'' MsgBox ("Sample address is " & ActiveSheet.ListObjects("SourceDataTable").DataBodyRange.SpecialCells(xlCellTypeVisible).Areas(sectionLoopRand).Columns(40).Cells(1, 1).Address)
sectionSampleSize = sectionSampleSize - 1
' MsgBox ("Sample selected")
End If
Loop
Auto filters can create non-contiguous ranges with multiple areas which can be problematic for normal range methods. One way is to loop through the visible cells and build an array of the addresses (or rows). Then by selecting an array element at random you can get the address of a cell in the visible range. For example
Option Explicit
Sub mysample()
Const TABLE_NAME = "SourceDataTable"
Const FILTER_COL = 1
Const TABLE_COL = 40 ' word sample added in table col 40
Const SAMPLE_TERM = "Product1"
Const SAMPLE_RATE = 10 ' 1 in 10 sampled
Const LOOP_MAX = 10000 ' avoid infinite while loop
Dim wb As Workbook, ws As Worksheet
Dim tbl As ListObject, rng As Range, t0 As Single
t0 = Timer
Set wb = ThisWorkbook
Set ws = wb.ActiveSheet
' apply filter and set rng to visible cells in filter col
Set tbl = ws.ListObjects(TABLE_NAME)
tbl.Range.AutoFilter Field:=FILTER_COL, Criteria1:=SAMPLE_TERM
Set rng = tbl.Range.Columns(FILTER_COL).SpecialCells(xlCellTypeVisible)
Debug.Print rng.Address, rng.Cells.Count
' build myrows array of addresses from rng.cells
Dim iCount As Integer, myrows() As String, cell As Range
iCount = -1 ' myrows(0) will be header
ReDim myrows(rng.Cells.Count)
For Each cell In rng.Cells
iCount = iCount + 1
myrows(iCount) = cell.Address
'Debug.Print iCount, cell.Address, cell.Row
Next
' determine sample size
Dim iSampleSize As Integer
If iCount > SAMPLE_RATE / 2 Then
iSampleSize = Round(iCount / SAMPLE_RATE, 0)
End If
'Debug.Print iSampleSize
' select sample
Dim n As Integer, x As Integer, z As Integer
n = 0
Do While n < iSampleSize
' pick one at random
x = 1 + Int(Rnd * iCount) ' avoid header row 0
'Debug.Print n, x
' update table if not previously chosen
If Len(myrows(x)) > 0 Then
ws.Range(myrows(x)).Offset(0, TABLE_COL - FILTER_COL) = "Sample"
myrows(x) = "" ' avoid repeat
n = n + 1
End If
z = z + 1 ' avoid endless loop
If z > LOOP_MAX Then
MsgBox "Max iterations in While Loop exceeded", vbCritical
Exit Sub
End If
Loop
MsgBox iSampleSize & " items selected from " & iCount, vbInformation, "Completed in " & Int(Timer - t0) & " secs"
End Sub
I have the following VBA code which, reads in multiple excel spreadsheets and sorts the data. I want to make a change to the code so that it replaces the zero values in the cells by the last non-zero value.
This is the code.
Option Explicit
Dim ReFH_files() As Variant
Dim num_ReFH_files As Integer
Dim Stations() As Variant
Dim num_stations As Integer
Dim Storm_Lengths() As Variant
Dim num_storm_lengths As Integer
Dim Total_Flow_files() As Variant
Dim WorkingFolder As String
Dim Return_Periods() As Integer
Dim num_return_periods As Integer
Dim root_name_ReFH As String
Dim root_name_TotalFlow As String
Dim root_name_StormLength As String
Dim header_text_to_match As String
Dim start_row As Integer
Dim start_col As Integer
Sub ProcessReFH_Files()
' Get the data and write it on the sheet for info
GetSummaryReFHData
' Create the Total Flow files from the refh files
ExtractTotalFlows
' Now create the ied files
CreateIEDFiles
End Sub
Sub SetWorkingFolder()
WorkingFolder = GetFolder
ActiveSheet.Cells(4, 11).Value = WorkingFolder
End Sub
Sub CreateIEDFiles()
Dim output_filename As String
Dim input_filename As String
Dim total_flow_filename As String
Dim fileOut As Integer
Dim fileIn As Integer
Dim station_name As String
Dim storm_length As String
Dim return_period As Integer
Dim i As Integer, j As Integer, k As Integer
Dim dataLine As String, outputLine As String
Dim dataArray As Variant
Dim time As Double, strTime As String
Dim flow As Double, strFlow As String
Dim num_data As Integer
' For each storm length create one ied file per return period
For i = 0 To num_storm_lengths - 1
storm_length = Storm_Lengths(i)
Debug.Print storm_length
For j = 0 To num_return_periods - 1
return_period = Return_Periods(j + 1)
Debug.Print return_period
' output file name
output_filename = root_name_StormLength & storm_length & "_Return_Period_" & return_period & ".ied"
Debug.Print output_filename
fileOut = FreeFile()
' Open the output file
output_filename = WorkingFolder & "\" & output_filename
Open output_filename For Output As #fileOut
' loop through the station files
For k = 0 To num_stations - 1
station_name = Stations(k)
' write the station standard station data
Print #fileOut, "QTBDY"
station_name = Replace(station_name, " ", "")
Print #fileOut, Trim(station_name)
total_flow_filename = GetTotalFlowFileName(station_name, storm_length)
Debug.Print total_flow_filename
input_filename = total_flow_filename
fileIn = FreeFile()
' Open the station file for this storm length and read the flow for this return period
input_filename = WorkingFolder & "\" & input_filename
Open input_filename For Input As #fileIn
' count the number of lines (this is very inefficient!
num_data = 0
While Not EOF(fileIn)
Line Input #fileIn, dataLine ' read in data 1 line at a time
If (Len(dataLine) > 1) Then
num_data = num_data + 1
End If
Wend
num_data = num_data - 1
Close #fileIn
' write the data header
'num_data = 120
outputLine = Right(Space(10) & num_data, 10)
outputLine = outputLine & " 0.000 0.000 HOURS EXTEND LINEAR 0.000"
Print #fileOut, outputLine
' open the file again
Open input_filename For Input As #fileIn
' Read the first line
Line Input #fileIn, dataLine
' read the rest of the lines, extracting the time and the flow for this return period
While Not EOF(fileIn)
Line Input #fileIn, dataLine ' read in data 1 line at a time
dataArray = Split(dataLine, ",")
flow = CDbl(dataArray(j + 1))
strTime = dataArray(0)
time = GetDecimalTime(strTime)
' make the numbers 3dp and string 10 characters wide
strFlow = Right(Space(10) & Format(flow, "0.000"), 10)
strTime = Right(Space(10) & Format(time, "0.000"), 10)
outputLine = strFlow & strTime
Print #fileOut, outputLine
Wend
Close #fileIn
Next k
' close the ied file
Close #fileOut
Next j
Next i
End Sub
Sub ExtractTotalFlows()
Dim i As Integer, j As Integer
Dim filename As String, output_filename As String
Dim fileNum As Integer, output_fileNum As Integer
Dim dataLine As String
Dim dataArray As Variant
Dim dataCols() As Integer
Dim num_cols As Integer
Dim outputLine As String
Dim i1 As Integer, i2 As Integer
Dim return_period As String
For i = 0 To num_ReFH_files - 1
filename = WorkingFolder & "\" & ReFH_files(i)
output_filename = WorkingFolder & "\" & Total_Flow_files(i)
fileNum = FreeFile()
Open filename For Input As #fileNum
output_fileNum = FreeFile()
Open output_filename For Output As #output_fileNum
' read the first line
Line Input #fileNum, dataLine ' read in data 1 line at a time
dataArray = Split(dataLine, ",")
' Get the columns where we want data
num_cols = 1
ReDim dataCols(0 To UBound(dataArray))
ReDim Return_Periods(0 To UBound(dataArray))
dataCols(0) = 0 ' time
For j = 0 To UBound(dataArray)
If (InStr(1, dataArray(j), header_text_to_match) > 0) Then
dataCols(num_cols) = j
' Take this opportunity to get the return period of this flow
' Find the first (
i1 = InStr(1, dataArray(j), "(")
' Find the next " "
i2 = InStr(i1 + 1, dataArray(j), " ")
' get the return period integer
return_period = Mid(dataArray(j), i1 + 1, i2 - i1)
Return_Periods(num_cols) = CInt(return_period)
' write it to the summary sheet
ActiveSheet.Cells(start_row + num_cols, start_col + 4).Value = return_period
num_cols = num_cols + 1
End If
Next j
ReDim Preserve dataCols(0 To num_cols - 1)
ReDim Preserve Return_Periods(0 To num_cols - 1)
num_return_periods = num_cols - 1
' Write out this data
outputLine = ""
For j = 0 To num_cols - 1
outputLine = outputLine & """" & dataArray(dataCols(j)) & """"
If (j <> num_cols - 1) Then
outputLine = outputLine & ","
End If
Next j
'Debug.Print outputLine
Print #output_fileNum, outputLine
' Now read and write the data
While Not EOF(fileNum)
Line Input #fileNum, dataLine ' read in data 1 line at a time
dataArray = Split(dataLine, ",")
outputLine = ""
For j = 0 To num_cols - 1
outputLine = outputLine & dataArray(dataCols(j))
If (j <> num_cols - 1) Then
outputLine = outputLine & ","
End If
Next j
Print #output_fileNum, outputLine
Wend
Close #fileNum
Close #output_fileNum
Next i
End Sub
Function GetSummaryReFHData()
Dim i As Integer
Dim i1 As Integer, i2 As Integer
Dim file_name As String
Dim station_name As String
Dim storm_length As String
Dim total_flow_file_name As String
'get the root names
root_name_ReFH = ActiveSheet.Cells(17, 4).Value
root_name_TotalFlow = ActiveSheet.Cells(18, 4).Value
root_name_StormLength = ActiveSheet.Cells(19, 4).Value
header_text_to_match = ActiveSheet.Cells(20, 4).Value
WorkingFolder = ActiveSheet.Cells(4, 11).Value
' read all the names of the files
ReFH_files = listfiles(WorkingFolder, root_name_ReFH)
num_ReFH_files = UBound(ReFH_files) + 1
' extract all of the station names
ReDim Total_Flow_files(0 To num_ReFH_files - 1)
ReDim Stations(0 To num_ReFH_files - 1)
ReDim Storm_Lengths(0 To num_ReFH_files - 1)
For i = 0 To num_ReFH_files - 1
file_name = ReFH_files(i)
' extract the station
' It is the characters from the end of the root name to the comma
i1 = Len(root_name_ReFH) + 1
i2 = InStr(1, file_name, ",")
station_name = Mid(file_name, i1, i2 - i1)
Stations(i) = station_name
' Make the total flow filename from this data
total_flow_file_name = root_name_TotalFlow & Mid(file_name, i1)
Total_Flow_files(i) = total_flow_file_name
' extract the storm length
' It is the characters from the comma to the -hr
i1 = InStr(1, file_name, ",") + 1
i2 = InStr(1, file_name, "-hr")
storm_length = Mid(file_name, i1, i2 - i1)
Storm_Lengths(i) = CInt(storm_length)
Next i
' Get the unique entries from these lists
Stations = ArrayUnique(Stations)
num_stations = UBound(Stations) + 1
Storm_Lengths = ArrayUnique(Storm_Lengths)
num_storm_lengths = UBound(Storm_Lengths) + 1
' Write the info found
Dim myrow As Integer, mycol As Integer
start_row = 7
start_col = 11 ' col K
' Clear any existing data
ActiveSheet.Range(Cells(start_row, start_col), Cells(start_row + 1000, start_col + 50)).Clear
myrow = start_row
ActiveSheet.Cells(myrow, start_col).Value = "Station names"
ActiveSheet.Cells(myrow, start_col).Font.Bold = True
ActiveSheet.Cells(myrow, start_col + 4).Value = "Return Periods"
ActiveSheet.Cells(myrow, start_col + 4).Font.Bold = True
For i = 0 To num_stations - 1
myrow = myrow + 1
ActiveSheet.Cells(myrow, start_col).Value = Stations(i)
Next i
myrow = myrow + 2
ActiveSheet.Cells(myrow, start_col).Value = "Storm lengths"
ActiveSheet.Cells(myrow, start_col).Font.Bold = True
For i = 0 To num_storm_lengths - 1
myrow = myrow + 1
ActiveSheet.Cells(myrow, start_col).Value = Storm_Lengths(i)
ActiveSheet.Cells(myrow, start_col + 1).Value = "hours"
Next i
myrow = myrow + 2
ActiveSheet.Cells(myrow, start_col).Value = "ReFH files"
ActiveSheet.Cells(myrow, start_col).Font.Bold = True
ActiveSheet.Cells(myrow, start_col + 5).Value = "Total Flowfiles"
ActiveSheet.Cells(myrow, start_col + 5).Font.Bold = True
For i = 0 To num_ReFH_files - 1
myrow = myrow + 1
ActiveSheet.Cells(myrow, start_col).Value = ReFH_files(i)
ActiveSheet.Cells(myrow, start_col + 5).Value = Total_Flow_files(i)
Next i
End Function
Function GetTotalFlowFileName(station_name As String, storm_length As String) As String
' returns the Total_Flow filename searching the Total_Flow_files array to match the station name and storm length
On Error GoTo err:
Dim i As Integer
Dim i2 As Integer
Dim station_storm_length_str As String
GetTotalFlowFileName = ""
For i = 0 To num_ReFH_files - 1
station_storm_length_str = station_name & ", " & storm_length
i2 = InStr(1, Total_Flow_files(i), station_storm_length_str)
If (i2 > 0) Then
GetTotalFlowFileName = Total_Flow_files(i)
Exit Function
End If
Next i
err:
i = 0
End Function
For example i have the following data which the code reads,
currently the code will get all the data the values and zero values and sort it into a new spreadsheet, what i would like to do is replace the zero values with the last non-zero value,
so before the table looks like this
0.221374522
0.211560734
0.202161408
0.193161194
0.184545026
0.176298167
0.168406246
0.160855274
0.153631665
0.146722248
0.140114266
0.133795387
0.127753695
0.121977691
0.116456288
0.111178801
0.106134945
0.101314819
0.096708904
0.092308046
0.088103451
0.084086673
0.080249602
0.076584455
0.073083763
0.069740363
0.066547387
0.063498248
0.060586636
0.057806503
0.055152054
0.052617739
0.050198244
0.047888479
0.045683572
0.04357886
0.041569879
0.039652357
0.037822209
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
After it should look like this
0.221374522
0.211560734
0.202161408
0.193161194
0.184545026
0.176298167
0.168406246
0.160855274
0.153631665
0.146722248
0.140114266
0.133795387
0.127753695
0.121977691
0.116456288
0.111178801
0.106134945
0.101314819
0.096708904
0.092308046
0.088103451
0.084086673
0.080249602
0.076584455
0.073083763
0.069740363
0.066547387
0.063498248
0.060586636
0.057806503
0.055152054
0.052617739
0.050198244
0.047888479
0.045683572
0.04357886
0.041569879
0.039652357
0.037822209
0.037822209
0.037822209
0.037822209
0.037822209
0.037822209
0.037822209
0.037822209
0.037822209
0.037822209
0.037822209
0.037822209
0.037822209
0.037822209
0.037822209
0.037822209
so it has copied the last value and replaced all the zero values with it.
The position where the zero terms start are different for different columns, so i am not sure how to get VBA to recognise the point where the cells go to zero and then how to instruct it to copy and replace the zero values with the last non-zero cell.
The huge code you have posted has nothing to do with Repeat last value in the cell to the end of the last row so I think it is not necessary. Please, post only relevant information.
Anyways, about your question, I would suggest to make a new SUB after all the process is done, and call it once all your data has been processed.
My code is designed if the list of numbers is in column A and it starts in row 1, and this data is the active sheet. Just adapt it to your needs.
Dim i As Long
Dim z As Long
i = Range("A" & Rows.Count).End(xlUp).Row
z = i
Do
If Cells(i, 1) > 0 Then 'If not zero, we drag this value to all rows below
Cells(i, 1).AutoFill Destination:=Range("A" & i & ":A" & z)
Exit Do
Else
i = i - 1
If i = 0 Then Exit Sub 'Is there is no zeros, then quit
End If
Loop
You don't mention where in this large amount of code your output example comes from so my answer will be quite generic. Store the value within the loop as PreviousValue and if the next iteration is 0 use PreviousValue instead.
Alternately, once the data has been imported you could loop backwards from the last row to the find the first non 0 value. Then loop from that cell forward replacing the 0. This may be better if there are occasional 0 values mid stream.
I have the following Excel sheet which has random number combinations build using numbers from 2 to 50 in set of 3, 2 and 1 in Column A.
I am trying to build whole possible combinations between Column A elements such that the obtained combination doesn't have any repeating numbers in them and contains all the number from 2 to 50.
My current code starts from A2 and builds only a single combination set. It doesn't evaluate other possible combinations with starting element as in A2, it then goes to A3 and then builds only one combination set using A3. This step continues for A4,A5...
This is my current code.
Private Sub RP()
Dim lRowCount As Long
Dim temp As String, s As String
Dim arrLength As Long
Dim hasElement As Boolean
Dim plans() As String, currentPlan() As String
Dim locationCount As Long
Dim currentRoutes As String
Dim line As Long
Worksheets("Sheet1").Activate
Application.ActiveSheet.UsedRange
lRowCount = ActiveSheet.UsedRange.Rows.Count
locationCount = -1
line = 2
Debug.Print ("*********")
For K = 2 To lRowCount - 1
currentRoutes = ""
For i = K To lRowCount
s = ActiveSheet.Cells(i, 1)
Do
temp = s
s = Replace(s, " ", "")
Loop Until temp = s
currentPlan = Split(Trim(s), ",")
arrLength = UBound(currentPlan) - LBound(currentPlan) + 1
hasElement = False
If Len(Join(plans)) > 0 Then
For j = 0 To arrLength - 1
pos = Application.Match(currentPlan(j), plans, False)
If Not IsError(pos) Then
hasElement = True
Exit For
End If
Next j
End If
If Not hasElement Then
currentRoutes = currentRoutes & (Join(currentPlan, ",")) & " "
If Len(Join(plans)) > 0 Then
plans = Split(Join(plans, ",") & "," & Join(currentPlan, ","), ",")
Else
plans = currentPlan
End If
End If
Next i
If locationCount < 0 Then
locationCount = UBound(plans) - LBound(plans) + 1
End If
If (UBound(plans) - LBound(plans) + 1) < locationCount Then
Debug.Print ("Invalid selection")
Else
Debug.Print (Trim(currentRoutes))
Worksheets("Sheet1").Cells(line, 11) = currentRoutes
line = line + 1
End If
Erase plans
Debug.Print ("*********")
Next K
End Sub
I have a vba module in Excel that had worked a few years ago but not now. I think something has changed (or someone made a change) but I am not sure what. The module is intended to compare the data in Column B (pre-sorted); for each single row or multiple row that matches it outputs a txt file. The first file whether a single row or multiple row is being created but then it stops. It does not go to the next row or group of rows and create a second file (.etc).
The code:
Sub OrderEC()
Dim Header(1 To 50) As Variant
Dim StartRow As Integer
Dim EndRow As Integer
Dim txt As String
Dim Rng1 As Range
Dim Rng2 As Range
Dim Rng3 As Range
Dim Count() As Variant
Dim x As Integer
Dim i As Integer
Dim Users As Integer
For i = 1 To 50
Header(i) = Cells(1, i)
Next
Set Rng1 = Range("B2:B10000")
For Each cell In Rng1
If cell.Value = "" Then GoTo First
ReDim Preserve Count(0 To 1, 0 To x) As Variant
For i = 0 To x - 1
If cell.Value = Count(1, i) Then
Count(0, i) = Count(0, i) + 1
GoTo First
End If
Next i
Count(1, x) = cell.Value
Count(0, x) = 1
x = x + 1
First:
Next
Users = UBound(Count, 2)
EndRow = 1
For s = 1 To Users
StartRow = EndRow
EndRow = StartRow + Count(0, s - 1)
DataFile = "C:\ECorder\" & "BULK_" & Cells(StartRow + 1, 2).Value & "_" & Format(DateTime.Now, "DDMMYYHHMMSS") & ".bulk"
Open DataFile For Output As #1
For U = 1 To 30
Print #1, Header(U) & "=" & Cells(StartRow + 1, U)
Next U
For v = 31 To 40
txt = Header(v) & "="
For i = 1 To Count(0, s - 1)
If i = 1 Then
txt = txt & Cells(StartRow + i, v)
Else
txt = txt & ", " & Cells(StartRow + i, v)
End If
Next i
Print #1, txt
Next v
For w = 41 To 44
Print #1, Header(w) & "=" & Cells(StartRow + 1, w)
Next w
Close #1
Next s
End Sub
Counting distinct values in excel - frequency function
yes I have read
Counting distinct values in excel - frequency function
I am try to count a column with different numbers
column contains (search)
1 3 7 9 5 1 3 9 4
result looking for;
C1 C2
1 = 2
2 = 0
3 = 2
4 = 1
etc
You can use COUNTIF to count the number of elements that match a condition.
Suppose you have your numbers in column A, say from A1 to A10:
A1: 1
A2: 3
A3: 7
etc...
Type in somewhere on your sheet, say in column B, the values you are interested in:
B1: 0
B2: 1
etc...
and in C1, type in
=COUNTIF($A$1:$A$10, B1)
This should count the number of values equal to B1 (i.e. 0), in A1:A10.
Enter your numbers in column A and a sequence in column B
A B
1 1
2 1
3 1
4 1
2 1
3 1
4 1
Select both columns and create a pivot table putting col A in rows. Select {COUNT} as function and you are done.
Not exactly what you are asking but i use a macro to generate frequency tables. I like it. Original code was posted by MWE at http://www.vbaexpress.com/kb/getarticle.php?kb_id=406 and i have (hopefully) improved it a bit. Have left in a little bit of redundant code so i get more replies :p
Sub zzzFrequencyDONT_SELECT_WHOLE_COLUMN()
' if user selects massive range - usually whole column - stops them
If Selection.Rows.Count > 60000 Then
MsgBox "Range selected is way too large - over 60,000. You have probably selected an entire column. Select a range of under 60,000 cells and try again"
End If
If Selection.Rows.Count > 60000 Then
Exit Sub
End If
'
' Function computes frequency count of unique values in a selection
'
Dim Count() As Integer
Dim I As Integer, J As Integer
Dim Num As Integer, NumOK As Integer, MaxNumOK As Integer, NumBad As Integer
Dim Row As Integer, Col As Integer, Temp1 As Integer, Temp2 As Integer
Dim strBuffer As String, strBadVals As String
Dim CellVal As Variant
Dim Ans As VbMsgBoxResult
Num = 0
NumBad = 0
NumOK = 0
MaxNumOK = 50
ReDim Count(MaxNumOK, 2)
strBuffer = ""
'
' sequence through each cell in selection
'
For Each Cell In Selection
Num = Num + 1
On Error Resume Next
CellVal = Cell.Value
Select Case Err
Case Is = 0
'
' no error, examine type
'
Select Case LCase(TypeName(CellVal))
Case "integer", "long", "single", "double"
'
' numeric type; if single or double, use
' Fix function to reduce to integer portion
'
If TypeName(CellVal) = "single" Or _
TypeName(CellVal) = "double" Then
CellVal = Fix(CellVal)
End If
'
' check if previously seen
' if so, simply bump counter
' if not, increment NumOK and store value
'
For I = 1 To NumOK
If CellVal = Count(I, 1) Then
Count(I, 2) = Count(I, 2) + 1
GoTo NextCell
End If
Next I
NumOK = NumOK + 1
If NumOK > MaxNumOK Then
MsgBox "capacity of freq count proc exceeded" & vbCrLf & _
"Displaying results so far", vbCritical
GoTo SortCount
End If
Count(NumOK, 1) = CellVal
Count(NumOK, 2) = 1
Case Else
NumBad = NumBad + 1
If Cell.Text <> "" Then
strBadVals = strBadVals & Cell.Text & vbCrLf
Else
strBadVals = strBadVals & "<blank>" & vbCrLf
End If
End Select
Case Is <> 0
NumBad = NumBad + 1
If Cell.Text <> "" Then
strBadVals = strBadVals & Cell.Text & vbCrLf
Else
strBadVals = strBadVals & "<blank>" & vbCrLf
End If
End Select
NextCell:
Next Cell
'
' counting done, sort data
'
SortCount:
For I = 1 To NumOK
For J = I To NumOK
If I <> J Then
If Count(I, 1) > Count(J, 1) Then
Call SwapVals(Count(I, 1), Count(J, 1))
Call SwapVals(Count(I, 2), Count(J, 2))
End If
End If
Next J
Next I
'
' store count data for display
'
Dim percentstore As Single
percentstore = Str(Count(I, 2)) / Str(Num)
For I = 1 To NumOK
strBuffer = strBuffer & Str(Count(I, 1)) & vbTab + Str(Count(I, 2)) & vbTab & FormatPercent(Str(Count(I, 2)) / Str(Num)) & vbCr
Next I
'
' display results
'
MsgBox "CTRL C to copy" & vbCrLf & _
"# cells examined = " & Str(Num) & vbCrLf & _
"# cells w/o acceptable numerical value = " & NumBad & vbCrLf & _
"# unique values found = " & NumOK & vbCrLf & _
"Frequency Count:" & vbCrLf & "value" & vbTab & "frequency" & vbTab & "Percent" & vbCr + strBuffer, vbInformation, "Frequency count - CTRL C to copy"
If NumBad > 0 Then
Ans = MsgBox("display non-numerics encountered?", vbQuestion & vbYesNo)
If Ans = vbYes Then MsgBox "Non Numerics encountered" & vbCrLf & strBadVals
End If
'
' write to worksheet?
'
' Ans = MsgBox("Ok to write out results below selection?" & vbCrLf + _
' "results will be two cols by " & (NumOK + 1) & " rows", vbQuestion + vbYesNo)
' If Ans <> vbYes Then Exit Sub
' Row = Selection.Row + Selection.Rows.Count
' Col = Selection.Column
' Cells(Row, Col) = "Value"
' Cells(Row, Col + 1) = "Count"
' For I = 1 To NumOK
' Cells(Row + I, Col) = Count(I, 1)
' Cells(Row + I, Col + 1) = Count(I, 2)
' Next I
End Sub
Sub SwapVals(X, Y)
'
' Function swaps two values
'
Dim Temp
Temp = X
X = Y
Y = Temp
End Sub