Excel VBA删除具有给定索引的混合值的行

时间:2013-11-21 16:26:11

标签: arrays function loops excel-vba vba

我有以下数据

Name     ID    Value

Alice    12C    500

Bob      14     60

Dan       15C    64

Dan       1C    25

Alice    4       556

Bob      11     455

在我的数据中,Alice同时具有数字(4)和字符串+数字ID(12C),我想删除所有Alice行,而我想保留其ID严格为数字的名称数据(Bob 11) ,14)或严格的字符串+数字(丹15C,1C)。

首先,我创建一系列唯一的名称条目:

   FinalRow = 7
   Name_column = 1
   n = 1

     Dim FID_Array() As Variant

          ReDim Preserve FID_Array(1 To 1)
          FID_Array(1) = Cells(2, Name_column)

     For j = 3 To FinalRow

        If Cells(j, Name_column).Value <> FID_Array(n) Then
                 ReDim Preserve FID_Array(1 To n + 1)
                 FID_Array(n + 1) = Cells(j, Name_column).Value
                 n = n + 1


        End If
     Next j

然后我创建一个包含特定名称的行号数组

ReDim Preserve Count_FID_Array(1 To 1) As Variant
  n = 1
  range_FID = A2:A7


' In my actual code this is Range_FID
' range_FID = Cells(2, FolderId_column).Address & ":" & Cells(FinalRow,  FolderId_column).Address

   For Each itm5 In FID_Array()

           Count_FID_Array(n) = Application.CountIf(" & range_FID & ", " & itm5 & ")
           ReDim Preserve Count_FID_Array(1 To n + 1)
           n = n + 1

    Next itm5

我认为我的CountIf不起作用。我试图将Count_FID_Array的值存储在另一个单元格中的另一个单元格中,但我得到了#value!

如果我得到countIf工作,那么我将按名称对数据进行排序,然后双循环以在下一个“n”次检查ID变量,以查看所有这些数字的最后一个数字是否为“C”或检查所有ID的ID是否为数字。

你能指出为什么我的countif不起作用并且有更聪明的方法吗?

我在这里使用名称数组,因为最后我想将数组提供给自动过滤器并删除我不想要的行。

更新1 2013年11月21日下午3:45:我已经解决了以下问题:

我基本上创建了三列。第一列是0或1,具体取决于ID是否都是数字。第二列是0或1,取决于最后一位是“C”(在我的实际工作中最后两位是“IB”),最后我将这些出现的频率与名称本身的频率进行了比较。如果其中任何一个匹配,那么我给它数字1,否则为0.我稍后使用此索引进行自动过滤。

现在我将尝试在VBA代码中使用zx8754更短的公式,我将尝试解决Joe提出的关于Countif的问题。

Sub conditionsforsubfolders()

  FinalColumn = Cells(1, Columns.Count).End(xlToLeft).Column
  FinalRow = Cells(Rows.Count, 1).End(xlUp).Row
  ActiveWorkbook.ActiveSheet.Columns(FinalColumn + 1).Insert
  ActiveWorkbook.ActiveSheet.Columns(FinalColumn + 2).Insert
  ActiveWorkbook.ActiveSheet.Columns(FinalColumn + 3).Insert

  Isnumber_Column = FinalColumn + 1
  Is_IB_Column = FinalColumn + 2
  Exceptions_Column = FinalColumn + 3
  Cells(1, Isnumber_Column) = "Number"
  Cells(1, Is_IB_Column) = "Letters"
  Cells(1, Exceptions_Column) = "Exceptions"

  For j = 1 To FinalColumn
     If Cells(1, j).Value = "TradeId" Then
         TradeId_column = j
     ElseIf Cells(1, j).Value = "Total Notional per folder" Then
         Total_Notional_Per_Folder_Column = j
     ElseIf Cells(1, j).Value = "ExternalId" Then
         ExternalId_Column = j
      ElseIf Cells(1, j).Value = "FolderId" Then
         FolderId_column = j

     End If
   Next j
   range_FolderId_fixed = Cells(2, FolderId_column).Address & ":" & Cells(FinalRow, FolderId_column).Address
   range_TradeId_fixed = Cells(2, TradeId_column).Address & ":" & Cells(FinalRow, TradeId_column).Address
   range_Isnumber = Cells(2, Isnumber_Column).Address & ":" & Cells(FinalRow, Isnumber_Column).Address(RowAbsolute:=False, ColumnAbsolute:=False)
   range_Isnumber_fixed = Cells(2, Isnumber_Column).Address & ":" & Cells(FinalRow, Isnumber_Column).Address
   range_Is_IB = Cells(2, Is_IB_Column).Address & ":" & Cells(FinalRow, Is_IB_Column).Address(RowAbsolute:=False, ColumnAbsolute:=False)
   range_Is_IB_fixed = Cells(2, Is_IB_Column).Address & ":" & Cells(FinalRow, Is_IB_Column).Address(RowAbsolute:=False, ColumnAbsolute:=False)
   range_FolderId_cell = Cells(2, FolderId_column).Address(RowAbsolute:=False, ColumnAbsolute:=False)
   range_TradeId_cell = Cells(2, TradeId_column).Address(RowAbsolute:=False, ColumnAbsolute:=False)
   range_Exceptions = Cells(2, Exceptions_Column).Address & ":" & Cells(FinalRow, Exceptions_Column).Address(RowAbsolute:=False, ColumnAbsolute:=False)


   Range(range_Isnumber).Formula = "=Isnumber(" & range_TradeId_cell & ")*1"
   Range(range_Is_IB).Formula = "=(RIGHT(" & range_TradeId_cell & ",2)= ""IB"")*1"

   Range(range_Exceptions).Formula = "=(SUMIF(" & range_FolderId_fixed & "," & range_FolderId_cell & "," & range_Isnumber_fixed & ")= COUNTIF(" & range_FolderId_fixed & "," & range_FolderId_cell & "))*1 +(SUMIF(" & range_FolderId_fixed & "," & range_FolderId_cell & "," & range_Is_IB_fixed & ")= COUNTIF(" & range_FolderId_fixed & "," & range_FolderId_cell & "))*1  "
  Worksheets("Sheet1").UsedRange.AutoFilter Field:=7, Criteria1:="=1"

End Sub

2 个答案:

答案 0 :(得分:2)

公式解决方案,没有VBA:

=IF(SUMPRODUCT(--($A$2:$A$7=A2),--(ISNUMBER($B$2:$B$7)))=1,"delete","keep")

enter image description here

答案 1 :(得分:1)

CountIF电话的问题在于您传递的是一个格式不正确的字符串。你实际上是在传递“range_FID & ", " & itm5”。

首先,设置为正确定义range_fid:

Dim range_fid As Range
Set range_fid = [A2:A7]

调用CountIF:

count_fid_array(n) = Application.WorksheetFunction.CountIf(range_fid, itm5)

话虽如此,我会采用不同的方式:

Dim c As Range
Dim people As Collection: Set people = New Collection
Dim person As Collection
Dim code As String

For Each c In Range(Range("a2"), Range("a2").End(xlDown)) ' loop through all rows
    If IsNumeric(c.Offset(0, 1)) Then ' check if the ID is numeric or not
        code = "num"
    Else
        code = "alphanum"
    End If

    On Error Resume Next  ' Needed in order to avoid error when person already exists in collection
    Set person = New Collection
    person.Add c.Value, "name"
    person.Add code, "code"
    people.Add person, c.Value ' will only be added if name doesn't already exist in collection
    On Error GoTo 0
    If people(c.Value)("code") <> code Then  ' if the format (alpha/num) of the ID on the current row is different than the format of a previous row for this name....
        people(c.Value).Remove ("code")  ' then set the code to "diff"
        people(c.Value).Add "diff", "Code"
    End If
Next

For Each person In people ' just display the content; you can take appropriate action here
    Debug.Print person("name") & ": " & person("code")
Next

结果是一个包含名称和每个代码的Collection。代码将是以下之一:

  • num :名称的所有值均为数字(Bob)
  • alphanum :名称的所有值均为字母数字(Dan)
  • diff :name至少有一个数字和字母数字(Alice)

请注意,使用Dictionary而不是Collection或使用Class可以更清楚地做到这一点,但我选择采用最简单的方法。