我有一个包含大约60,000条记录的数据集。拖欠日期字段紧跟在处理货币值的字段之后,有时用户意外地在拖欠日期字段中输入货币值。此外,他们有时会以字符串形式输入日期(2011年8月2日)或违约天数(135或135天)。最常见的输入方法是mm / dd / yy格式(08/02/11)。
可悲的是,这个系统的程序员拒绝花时间为这个领域创建验证,所以在获得数据之后我必须尽可能多地执行它。通常情况下,我会用一些简单的公式来处理这个问题,但是,用户输入数据有19种不同的方式,我需要能够快速处理它们中的每一个。将列加载到数组中似乎是最佳选择。
我的想法是将列加载到数组中,循环遍历它,处理所有条目选项(或删除那些完全搞砸的选项),然后将其写回工作表。 我知道数据类型是下面数组的第一个问题,但我之前只在Excel VB中使用了一次数组,并且我不太确定我做错了什么。第三行代码是第一个问题。感谢您的帮助。
BRETTDJ评论的工作代码
'Perform housekeeping on delinquency date
Dim delinquency()
delinquency = Application.Transpose(Range("AH1:AH" & importwsRowCount))
For i = LBound(delinquency) To UBound(delinquency)
If InStr(delinquency(i), ".") Then
delinquency(i) = Empty
Debug.Print "Emptied an array element at row " & i + 1
End If
'Additional string or numeric operations here to reformat bad entries.
Next i
Set delRange = Range("AJ1:AJ" & importwsRowCount)
iWS.names.Add Name:="dRange", RefersTo:=delRange
delinquency = Application.Transpose(delinquency) 'Transpose rows and columns
Range("dRange").Value = delinquency 'Write array to worksheet
需要重新调整的坏的进入示例
<击>的九月25,20 (没有年份,没有年份!删除。)
SEPT (没有年份,没用,删除。)
N / A (垃圾!已删除。)
LONG TIME AG (什么白痴认为这是一个好主意,删除。)
6月30日,200 (显然该字段只能容纳12个字符,删除。)
收费(无用,删除。)
94 DAYS (获取空格前的所有字符,并从包含订单日期的其他字段中减去以获取拖欠日期。)
94 DPD (DPD在某些人心目中代表我过去的天过去。与上述相同。)
2008-7-15 12 (不确定是什么附加号码,在空格和转换前拍摄所有字符。)
INVALID (删除。)
BLANK (什么也不做。)
12282009 (使用嵌套的LEFT和RIGHT,并在/之间使用CONCATENATE。)
9202011 (添加前导零,然后与上面相同。)
92410 (添加前导零,这将转换为09/24/10)
41261 (自1899年12月31日起的天数,这将转变为2012年8月12日)
1023 (逾期的天数,从ORDER DATE减去以获取拖欠日期。)
452 (与上述相同。)
12 (与上述相同。)
1432.84 (货币价值,被低智商错误输入。删除。)
更新了包含删除错误条目的代码(正在进行中)
'Perform housekeeping on delinquency date
Columns("AH:AH").Select
Selection.NumberFormat = "0"
Selection.Copy
Selection.PasteSpecial Paste:=xlValues, Operation:=xlNone, SkipBlanks:= _
True, Transpose:=False
Dim delinquency()
ReDim del(1 To importwsRowCount, 1 To 1)
del = Range("AH1:AH" & importwsRowCount).Value
For i = LBound(del, 1) To UBound(del, 1)
delChars = Len(del(i, 1)) 'Determine length of entry
If IsNumeric(del(i, 1)) = True Then 'Determine datatype of entry
delType = "Numeric"
Else
delType = "String"
End If
If InStr(del(i, 1), ".") Then 'Removes monetary entries like 142.84
del(i, 1) = Empty
ElseIf InStr(del(i, 1), "*") Then 'Removes ***INVALID*** entries
del(i, 1) = Empty
ElseIf delChars = 12 Then 'Removes all entries that extend beyond the 12 character limit of the field and get cut off
del(i, 1) = Empty
ElseIf delType = "String" And Len(del(i, 1).Value) < 10 And InStrRev(del(i, 1).Value, " ") Then 'Takes the number from entries like 2194 Days or 23 DPD
del(i, 1).Value = Left(del(i, 1).Value, Len(del(i, 1).Value) - InStrRev(del(i, 1).Value, " "))
If IsNumeric(del(i, 1)) = False Then 'If the characters to the left of the space are not numbers, discard
del(i, 1).Value = Empty
Else
del(i, 1).Value = Format((CLng(Range("E" & i + 1).Value) - Abs(del(i, 1).Value)), "mm/dd/yy") 'Pull order date and subtract days from it for delinquency date
End If
ElseIf delType = "Numeric" And Len(del(i, 1)) = 5 Then
If del(i, 1).Value > CLng(Date) Then 'Value is greater than todays date, improperly formated date that needs character manipulation and / added
del(i, 1).Value = Format(del(i, 1).Value, "000000") 'Add leading zero
del(i, 1).Value = DateSerial(Right(del(i, 1).Value, 2), Left(del(i, 1).Value, 2), Right(Left(del(i, 1).Value, 2), 4)) 'Grab year, then month, then day for serialize
Else
del(i, 1).Value = Format(del(i, 1).Value, "mm/dd/yy") 'Properly formated date that just needs format conversion
End If
ElseIf delType = "Numeric" And (delChars = 7 Or delChars = 8) Then
If delChars = 7 Then
del(i, 1).Value = Format(del(i, 1).Value, "00000000") 'Add leading zero
End If
del(i, 1).Value = DateSerial(Right(del(i, 1).Value, 4), Left(del(i, 1).Value, 2), Right(Left(del(i, 1).Value, 2), 6)) 'Grab year, then month, then day for serialize
ElseIf delType = "Numeric" And delChars < 5 Then
del(i, 1).Value = Format((CLng(Range("E" & i + 1).Value) - Abs(del(i, 1).Value)), "mm/dd/yy")
End If
Next i
Set dRange = Range("AJ1:AJ" & importwsRowCount)
iWS.names.Add Name:="dRange", RefersTo:=delRange
delinquency = Application.Transpose(delinquency) 'Transpose rows and columns
Range("dRange").Value = delinquency 'Write array to worksheet
答案 0 :(得分:1)
行
的原因delinquency = Application.Transpose(["AH1:AH" & importwsRowCount])
错误是["AH1:AH" & importwsRowCount]
无效(它返回一个字符串,而不是范围)。
[...]
是Evaluate
方法的快捷方式。要让它返回范围引用,您需要执行类似[AH1:AH60000]
的操作,即不使用""
。最好引用传统的范围
delinquency = Application.Transpose(Range("AH1:AH" & importwsRowCount]))
也就是说,如果您将Transpose
声明为2D数组,则实际上不需要使用delinquency
。
ReDim delinquency(1 To importwsRowCount, 1 To 1)
因此,您的代码变为
Dim delinquency() As Variant
ReDim delinquency(1 To importwsRowCount, 1 To 1)
delinquency = Range("AH1:AH" & importwsRowCount).Value
For i = LBound(delinquency, 1) To UBound(delinquency, 1)
If InStr(delinquency(i, 1), ".") Then
delinquency(i, 1) = Empty
End If
'MANY ADDITIONAL OPERATIONS HERE
Next i
Set delRange = Range("AJ1:AJ" & importwsRowCount)
iWS.Names.Add Name:="dRange", RefersTo:=delRange
Range("dRange").Value = delinquency 'Write array to worksheet
注意:
Range("AH1:AH" & importwsRowCount)
是指ActiveSheet
Dim wsData as Worksheet
Set wsData = ActiveSheet ' or whatever sheet you want
delinquency = wsData.Range("AH1:AH" & importwsRowCount).Value
Set delRange = wsData.Range("AJ1:AJ" & importwsRowCount) 'assuming you want to refer to the same sheet
iWS.Names.Add Name:="dRange", RefersTo:=delRange ' not sure what this is for, but be sure your Name referes tot he right sheet
' Might be better to use this, if you need to use the Name at all
iWS.Names("dRange").RefersToRange = delinquency
答案 1 :(得分:1)
鉴于你接受了Chris后来的帖子,其部分涵盖了我之前评论的相同内容,我已将此帖更新为这些更改的答案(我先前评论中标记的第一个)
Redim
变量数组。它是一条冗余线,因为变量阵列自动适合输入的范围
<击> ReDim delinquency(1 To importwsRowCount, 1 To 1)
击> Value2
进行轻微调整,但使用范围时优于默认Value
然后,您可以选择设置定义为 rows x columns 或 columns x rows 的变体数组。
通常采用第一种方法,因为转换仅在
时才需要Transpose
)ReDim
将用于调整数组行的大小。使用Redim Preserve
时,只能调整最后一个维度的大小。因此,如果您以后想要减少与数组中行相关的数据量,则需要使用Transpose
设置数组以生成列x行 我在variant arrays上的文章位于EE付费专区之外。你能再试一次吗?
标准用法
Sub RowByColumn()
Dim delinquency()
delinquency = Range("AH1:AH" & importwsRowCount).Value2
转置用法
Sub ColumnByRow()
'creates a 1D array when working on a single column or row. creates a *column X row* array on a 2D array
Dim delinquency()
delinquency = Application.Transpose(Range("AH1:AH" & importwsRowCount).Value2)