1

約 60,000 レコードを含むデータ セットがあります。延滞日フィールドは、金額を扱うフィールドの直後にあり、ユーザーが誤って延滞日フィールドに金額を入力することがあります。さらに、日付を文字列 (2011 年 8 月 2 日) または滞納日数 (135 日または 135 日) として入力することもあります。最も一般的な入力方法は、mm/dd/yy 形式 (08/02/11) です。

悲しいことに、このシステムのプログラマーは、このフィールドの検証の作成に時間を費やすことを拒否しているため、データを取得した後、できる限り多くの検証を実行する必要があります。通常、これはいくつかの簡単な数式で処理しますが、ユーザーがデータを入力する方法は 19 通りあり、それぞれをすばやく処理できる必要があります。列を配列にロードすることが最良の選択肢のようです。

私の考えは、列を配列にロードし、それをループして、すべてのエントリ オプションを処理し (または完全に台無しになっているオプションを削除して)、それをワークシートに書き戻すことです。以下の配列の最初の問題はデータ型であることはわかっていますが、以前に Excel VB で配列を使用したことが一度しかなく、何が間違っているのかよくわかりません。コードの 3 行目は最初の問題です。ご協力いただきありがとうございます。

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

9 月の再フォーマットが必要な不適切なエントリの
例 25, 20 (いいえ、いいえ、削除してください。)
SEPT (いいえ、役に立たない、削除してください。)
N/A (くだらない! 削除してください。)
LONG TIME AG (ばかがこれを良い考えだと思った、削除してください。)
JUNE 30 , 200 (どうやらこのフィールドは 12 文字しか保持しないようです。削除します。)
CHARGED OFF (役に立たない、削除します。)
94 DAYS (スペースの前にあるすべての文字を取り、注文日を含む他のフィールドから差し引いて、延滞日を取得します。)
94 DPD (DPD in 2008-7-15
12 (追加の数字が何かわからないので、スペースの前のすべての文字を取り、変換してください。)
INVALID (削除します。)
BLANK (何もしません。)
12282009 (ネストされた LEFT と RIGHT を使用し、間に / を挟んで CONCATENATE を使用します。)
9202011 (先行ゼロを追加し、上記と同じです。)
92410 (先行ゼロを追加します。これは 09/ に変換されます24/10)
41261 (1899 年 12 月 31 日からの日数、これは 12/08/12 に変換されます)
1023 (滞納日からの日数、ORDER DATE から減算して滞納日を取得します。)
452 (上記と同じ。)
12 (同じ
。 1432.84 (金銭的価値、IQの低い下僕が誤って入力したもの。削除します。)

不正なエントリの削除を含む更新されたコード (進行中の作業)

'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
4

2 に答える 2

1

私の以前のコメントと同じ根拠を部分的にカバーしたChrisからの後の投稿を受け入れたので、これらの変更を加えた回答としてこの投稿を更新しました(以前のコメントで最初にフラグが付けられたもの)

  1. Redim範囲をキャプチャするために使用する前に、バリアント配列を使用する必要はありません。バリアント配列は入力される範囲に自動的に適合するため、これは冗長な行です。
    ReDim delinquency(1 To importwsRowCount, 1 To 1)
  2. わずかな微調整ですが、範囲を操作する場合Value2はデフォルトよりも優れていますValue

次に、行 x 列または列 x 行として定義されるバリアント配列を設定することを選択できます。

通常、変換が必要になるのは次のいずれかの場合のみであるため、最初の方法が使用されます。

  1. 単一の列または行で作業していて、1D 配列で作業したい (質問によると、はい、Transposeまだ必要です)
  2. 後でReDim、配列行のサイズを変更するために使用されます。を使用するRedim Preserveと、最後の寸法のみがサイズ変更できます。したがって、後で配列内の行に関連するデータの量を減らしたい場合は、列 x 行Transposeを生成するように配列をセットアップする必要があります。

バリアント配列に関する私の記事は、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)
于 2012-11-06T22:39:20.063 に答える
1

ラインの理由

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

エラーは["AH1:AH" & importwsRowCount]無効です (範囲ではなく文字列を返します)。

[...]Evaluateメソッドへのショートカットです。範囲参照を返すようにするには[AH1:AH60000]"". 従来通り範囲を参照した方が良いでしょう

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

とは言っても、2D 配列としてTranspose宣言する場合は、実際に使用する必要はありません。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

ノート:

  1. Range("AH1:AH" & 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
于 2012-11-06T06:00:46.787 に答える