【问题标题】:Excel VB - Read Column into 1D Array, Perform Ops, Write Back to Named Range?Excel VBA - 将列读入一维数组,执行操作,写回命名范围?
【发布时间】:2012-10-26 00:54:33
【问题描述】:

我有一个包含大约 60,000 条记录的数据集。拖欠日期字段紧跟在处理货币值的字段之后,有时用户会在拖欠日期字段中意外输入货币值。此外,他们有时将日期输入为字符串(2011 年 8 月 2 日)或拖欠天数(135 或 135 天)。最常见的输入方法是 mm/dd/yy 格式 (08/02/11)。

遗憾的是,这个系统的程序员拒绝花时间为这个字段创建验证,所以我必须在获得数据后尽可能多地执行它。通常,我会用一些简单的公式来处理这个问题,但是,用户输入数据有 19 种不同的方式,我需要能够快速处理每一种方式。将列加载到数组中似乎是最好的选择。

我的想法是将列加载到数组中,循环遍历它,处理所有条目选项(或删除完全混乱的选项),然后将其写回工作表。 我知道数据类型是下面数组的第一个问题,但我之前在 Excel VB 中只使用过一次数组,我不太确定我做错了什么。第三行代码是第一个问题。感谢您的帮助。

BRTTDJ 评论的工作代码

'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

需要重新格式化的错误输入示例
9 月。 25, 20(没有年份,没有年份!删除。)
SEPT(没有年份,没用,删除。)
N/A (垃圾!已删除。)
LONG TIME AG(傻瓜认为这是个好主意,删除。)
200 年 6 月 30 日(显然该字段只能包含 12 个字符,请删除。)
CHARGED OFF(没用,请删除。)
94 DAYS(取空格前的所有字符并从包含订单日期的其他字段中减去以获得拖欠日期。)
94 DPD(我相信,在某些聪明人看来,DPD 代表逾期天数。与上述相同。)
2008-7-15 12(不确定附加数字是多少,取之前的所有字符空格和变换。)
INVALID(删除。)
空白(什么都不做。)
12282009(使用嵌套的 LEFT 和 RI GHT 和 CONCATENATE 与 / 之间。)
9202011(添加前导零,然后同上。)
92410(添加前导零,这将转换为 09/24/10)
41261(自 1899 年 12 月 31 日以来的天数,这将转换为 12/08/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

【问题讨论】:

  • 首先要做的是给你的老板一个金钱估计,你和你的企业在这个数据质量问题上浪费了多少时间和金钱。然后他可以决定是否值得正确修复。数据存储在哪里?在数据库中?您可能可以编写一个 UPDATE 语句来永久修复数据。
  • ElectricLlama,哈哈,我希望它是那么容易。这是一个 CSV 文件,我可以从用于管理我们行业帐户的门户下载。该门户网站在全国范围内被许多大公司使用。从本质上讲,它具有广泛的行业接受度,具有讽刺意味的是,因为它确实如此,所以编程人员是赤裸裸的。他们收取订阅费而不提供支持。该系统包含高度机密的财务信息,我绝不会获得访问权限。
  • 您可能会发现我在Using Variant Arrays in Excel VBA for Large Scale Data Manipulation 上写的这篇文章很有用。有关您的问题的详细帮助,您需要提供更多 *好数据/坏数据示例 *
  • Brettdj,成功了!您的示例应该只有一个等号,对吗?现在来弄清楚如何在 VB 中使用一些正则表达式来理顺这些条目。
  • 删除此行ReDim delinquency(importwsRowCount) 将您的转置行更改为此delinquency = Application.Transpose(Range("AH1:AH" &amp; importwsRowCount))

标签: arrays types excel for-loop vba


【解决方案1】:

行的原因

delinquency = Application.Transpose(["AH1:AH" & importwsRowCount]) 

错误是["AH1:AH" &amp; importwsRowCount] 无效(它返回一个字符串,而不是一个范围)。

[...]Evaluate 方法的快捷方式。要让它返回一个范围引用,您需要执行[AH1:AH60000] 之类的操作,即没有""。最好按照惯例引用范围

delinquency = Application.Transpose(Range("AH1:AH" & importwsRowCount]))

也就是说,如果将 delinquency 声明为二维数组,则实际上不需要使用 Transpose

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

注意事项:

  1. Range("AH1:AH" &amp; importwsRowCount) 指的是ActiveSheet 上的一个范围
  2. 为了保持稳健,您应该在工作表引用中明确说明。所以使用类似的东西

.

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

【讨论】:

    【解决方案2】:

    鉴于您接受了 Chris 的后续帖子,该帖子部分涵盖了与我之前评论相同的内容,我已更新此帖子作为这些更改的答案(我之前评论中标记的第一个)

    1. 在使用变量数组捕获您的范围之前,无需Redim。这是一条多余的行,因为变量数组会自动适应输入的范围。
      ReDim delinquency(1 To importwsRowCount, 1 To 1)
    2. 稍作调整,但在使用范围时使用 Value2 比默认的 Value 更好

    然后,您可以选择设置定义为 rows x columnscolumns x rows 的变体数组。

    通常采用第一种方法,因为只有在以下任一情况下才需要转换

    1. 您正在使用单列或单行,并且想要使用一维数组(根据您的问题 - 所以仍然需要 Transpose
    2. 稍后的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)
    

    【讨论】:

    • 酷!通过 microsoft.com:Value2 和 Value 属性之间的唯一区别是 Value2 属性不使用 Currency 和 Date 数据类型。您可以使用 Double 数据类型将使用这些数据类型格式化的值作为浮点数返回。
    • 我确实阅读了您的文章,因为我使用 OSX 10.8.2 和 Excel for Mac 2011,我认为我无法访问该 Regex 库?这似乎是一个 Windows 的东西。我目前可以将数组写回工作表,尽管当我尝试在循环遍历数组时进行数据操作时收到错误。我的另一篇文章对此进行了更好的讨论。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-12-05
    • 2017-10-01
    • 2013-12-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-09-07
    相关资源
    最近更新 更多