【问题标题】:How to sort and concatenate a column range with VBA如何使用 VBA 对列范围进行排序和连接
【发布时间】:2019-04-03 15:38:05
【问题描述】:

我为特定订单号 (C2:C100) 生成了零件号 (A2:A100) 及其数量 (B2:B100) 的列表。我正在编写一个子程序,它将过滤每个唯一零件号的零件号列表,然后创建一个新列表,其中包含每个零件的总数量以及将使用它的每个订单。

我有一个子成功创建唯一零件编号列表 (F8:F100),然后另一个子自动过滤每个唯一零件编号的零件编号主列表 (A2:A100) 并为该特定零件的订单号 (C2:C100)。我试图连接订单号的范围,但我的功能失败了。

Sub WOSorter()
    Dim rng As Range
    Dim WOrng As Range
    Dim i As Long
    Dim Limit As Long
    Dim seperator As String

    seperator = ", "

    Limit = Worksheets("Selector").Range("F8:F100").Cells.SpecialCells(xlCellTypeConstants).Count - 1

    For i = 0 To Limit
    Set rng = Worksheets("Selector").Cells(8 + i, 6)
        With Worksheets("Selector").Range("A1")
        .AutoFilter Field:=1, Criteria1:=rng
            Set WOrng = Worksheets("Selector").Range("C2:C100").Cells.SpecialCells(xlCellTypeVisible)
            Worksheets("Selector").Cells(8 + i, 9).Value = ConcatenateRange(WOrng, seperator)
        End With
    Next

    If Worksheets("Selector").AutoFilterMode Then Worksheets("Selector").AutoFilter.ShowAllData

End Sub

-----------------------------------------------------------------------------

Function ConcatenateRange(ByVal WOrng As Range, Optional ByVal seperator As String) As String

Dim newString As String
Dim cellArray As Variant
Dim i As Long, j As Long

cellArray = WOrng.Value

For i = 1 To UBound(cellArray, 1)
    For j = 1 To UBound(cellArray, 2)
        If Len(cellArray(i, j)) <> 0 Then
            newString = newString & (seperator & cellArray(i, j))
        End If
    Next
Next

If Len(newString) <> 0 Then
    newString = Right$(newString, (Len(newString) - Len(seperator)))
End If

ConcatenateRange = newString

End Function

我目前在线上遇到类型不匹配错误:

For i = 1 To UBound(cellArray, 1)

如果原始列表在 colA、B、C 中,并且在 colF 中具有唯一的部件号:

colA      colB     colC               colF
123-4     1        01111              123-4
456-7     2        02222              456-7
123-4     1        03333              789-0 
789-0     1        04444
456-7     3        05555

那么结果应该是:

colA      colB     colC               colF         colI
123-4     1        01111              123-4        01111, 03333
456-7     2        02222              456-7        02222, 05555 
123-4     1        03333              789-0        04444
789-0     1        04444
456-7     3        05555

【问题讨论】:

  • 请参阅此处以了解应该更好的其他功能:stackoverflow.com/questions/54582741/…
  • 哦,当你有隐藏的行时,错误可能会出现。您不能批量加载范围不连贯的数组。
  • @ScottCraner。感谢你的回复。我的函数库中确实有 TEXTJOIN() 可用,但我不确定它是否可以在这里使用,因为我的 colA 列表是可变的并且可能有数千个唯一值。
  • @ScottCraner 由于数组无法加载不相交的范围,所以我会将不相交的范围复制到另一张纸上。然后将该连续范围加载到数组中。希望这会奏效。
  • 你试过我下面的答案了吗?

标签: excel vba


【解决方案1】:

使用链接上的函数将您的代码更改为:

Sub WOSorter()

    Dim seperator As String
    seperator = ", "

    With Worksheets("Selector")
        Dim lstrow As Long
        lstrow = .Cells(.Rows.Count, "F").End(xlUp).Row


        Dim i As Long
        For i = 2 To lstrow
            .Range("I" & i).Value = TEXTJOINIFS(.Range("C:C"), seperator, .Range("A:A"), .Range("F" & i).Value)
        Next i

     End With


End Sub

这不依赖于不允许批量加载数组的过滤器。

这里是 textjoinifs 函数:

Function TEXTJOINIFS(rng As Range, delim As String, ParamArray arr() As Variant) As String
    Dim rngarr As Variant
    rngarr = Intersect(rng, rng.Parent.UsedRange).Value

    Dim condArr() As Boolean
    ReDim condArr(1 To Intersect(rng, rng.Parent.UsedRange).Rows.Count) As Boolean

    TEXTJOINIFS = ""

    Dim i As Long
    For i = LBound(arr) To UBound(arr) Step 2
        Dim colArr() As Variant
        colArr = Intersect(arr(i), arr(i).Parent.UsedRange).Value
        Dim j As Long
        For j = LBound(colArr, 1) To UBound(colArr, 1)

            If Not condArr(j) Then
                Dim charind As Long
                charind = Application.Max(InStr(arr(i + 1), ">"), InStr(arr(i + 1), "<"), InStr(arr(i + 1), "="))
                Dim opprnd As String
                If charind = 0 Then
                    opprnd = "="
                Else
                    opprnd = Left(arr(i + 1), charind)
                End If
                Dim t As String
                t = """" & colArr(j, 1) & """" & opprnd & """" & Mid(arr(i + 1), charind + 1) & """"
                If Not Application.Evaluate(t) Then condArr(j) = True
            End If
        Next j
    Next i

    For i = LBound(rngarr, 1) To UBound(rngarr, 1)
        If Not condArr(i) Then
            TEXTJOINIFS = TEXTJOINIFS & rngarr(i, 1) & delim
        End If
    Next i
    If TEXTJOINIFS <> "" Then
        TEXTJOINIFS = Left(TEXTJOINIFS, Len(TEXTJOINIFS) - Len(delim))
    End If

End Function

这是输出:

【讨论】:

  • 我做到了,但不幸的是在行上遇到了运行时 5 错误“无效的过程或调用参数”
  • TEXTJOINIFS = Left(TEXTJOINIFS, Len(TEXTJOINIFS) - Len(delim))
  • 出错时lstrow 的值是多少?作为 F 列中的最后一行数据有意义吗?
  • 我在 colF 中的列表从第 8 行开始,上面有一些文本标题,如果这有什么不同的话。 colI TEXTJOINS 然后从 I8 开始。
  • 我使 TEXTJOINIFS 更加健壮,请参阅编辑。确保将 sub 中的循环开始更改为从第一行数据开始。我使用 2 因为这是我的数据开始的地方,那么你的数据可能是 8:For i = 8 To lstrow
猜你喜欢
  • 2018-05-13
  • 2015-06-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-12-27
  • 1970-01-01
相关资源
最近更新 更多