如何将一个范围的SpecialCell分配给新范围?

时间:2011-08-23 05:11:06

标签: excel excel-vba vba

我知道我可以通过迭代第一个范围来完成此任务,但我很想知道是否可以使用SpecialCells属性来完成它。

假设我有一列名称,其间有空单元格:

 A     B    C
Jon
Jim
Sally

Jane


Mary

如果我想使用VBA复制已用过的单元格,我可以说

Range("A1:A8").SpecialCells(xlCellTypeConstants, xlTextValues).Copy
Range("C1:C"&Range("A1:A8").SpecialCells(xlCellTypeConstants, xlTextValues).Count).PasteSpecial

并以

结束
 A     B    C
Jon        Jon
Jim        Jim
Sally      Sally
           Jane    
Jane       Mary


Mary

相反,我希望能够在不必在任何地方粘贴范围的情况下执行此操作。

我希望能够做的是包含[Jon,Jim,Sally,Jane,Mary]的范围,但是如果我尝试Set rng = Range("A:A").SpecialCells(xlCellTypeConstants,xlTextValues),我最终会将空格作为范围的元素,或者使用硬编码的单元格范围,其中一个单元格在到达空间之前仅计算[Jon, Jim, Sally]

我希望能够在代码中的其他地方使用范围,我认为SpecialCells是一种很好的紧凑方式,但我是唯一的替代方法,它可以在循环中进行,并将单元格比作{{ 1}}?

3 个答案:

答案 0 :(得分:4)

考虑以下代码

Dim r As Range
Set r = Range("A:A").SpecialCells(xlCellTypeConstants, xlTextValues)

Debug.Print r.Rows.Count, r.Cells.Count
' returns:        3            5 

上面唯一可靠的信息是r.Cells.CountRows在第一个空格处被切断。我想这会混淆整个粘贴过程。因此,您无法将r直接粘贴到工作表中。

您可以将其传输到Variant数组,然后将其打印到工作表上。但是怎么做呢?好吧,r.Cells类似于一个集合。也许将它转换为这样的数组:

Dim i As Long
Dim c As Range
Dim v As Variant
ReDim v(1 To r.Cells.Count, 1 To 1)
i = 0
For Each c In r
    i = i + 1
    v(i, 1) = c
Next c
Range("B1").Resize(UBound(v,1),UBound(v,2)) = v

无需检查空单元格。

你也可以使用Chip Pearson的CollectionToArray procedure,这基本上是对上述代码的一种更好的实现,可能需要稍加修改。

顺便说一句,检查<> ""不会拒绝值为空字符串""的单元格。如果您必须检查真正的空/“空白”单元格,那么IsEmpty会更安全。

*在此上下文中为@Issun提供“slap”的信用。

答案 1 :(得分:2)

如果你真的想要使用特殊的单元,你需要为每个循环做一个,但是这里是如何在没有变量数组或检查空单元格的情况下进行的。请注意,我正在反向使用字典(请参阅下面的注释)将单元格存储为项目(而非键),因此我可以使用.Items方法,该方法会吐出字典中所有项目的数组。

Sub test()

Dim cell As Range
Dim i As Long
Dim dict As Object
Set dict = CreateObject("scripting.dictionary")

For Each cell In Range("A1:A10").SpecialCells(xlCellTypeConstants)
    dict.Add i, cell.Value
    i = i + 1
Next

Sheet1.Range("c1").Resize(dict.Count).Value = _
Application.Transpose(dict.items)

End Sub

但是如果您使用相当大的范围,有一种更快的方法可以做到这一点。使用字典对象,因为它能够吐出其中的所有键/项的数组(您可以将其转置到范围)。集合没有这种可靠性,但字典只允许每个密钥中的一个。工作?反向使用字典,将值作为项目和键的计数器放置!

以下是如何使用变体数组/字典(允许使用dupes)的示例:

Sub test()

Dim vArray As Variant
Dim i As Long, j As Long, k As Long
Dim dict As Object
Set dict = CreateObject("scripting.dictionary")

vArray = Range("A1:A10").Value

For i = 1 To UBound(vArray, 1)
    For j = 1 To UBound(vArray, 2)
        If Len(vArray(i, j)) <> 0 Then
            dict.Add k, vArray(i, j)
            k = k + 1
        End If
    Next
Next

Sheet1.Range("c1").Resize(dict.Count).Value = _
Application.Transpose(dict.items)

End Sub

这比使用特殊单元格快得多(因为VBA在不咨询Excel的情况下处理工作)并且您可以像使用粘贴一样使用转置,所以我更喜欢这种方法。

正如JFC所指出的那样,使用字典对象似乎并没有太多好处,最大的原因是它可以很容易地转换数组,你也可以将它水平转置,这非常有趣。 / p>

Sheet1.Range(Cells(1, 3), Cells(1, dict.Count + 2)).Value = _ 
Application.Transpose(Application.Transpose(dict.items)) 

答案 2 :(得分:1)

由于Range对象代表实际的单元格(A1A2A3A5A8(在本例中),我不认为你可以压缩5个连续的单元格范围,而不必粘贴在任何地方。

但是,如果你需要循环它,你不需要使用比较,使用For Each将跳过空白:

Set Rng = Range("A1:A8").SpecialCells(xlCellTypeConstants, xlTextValues)
Print Rng.count
 5 
For Each cell in Rng: Print cell: Next cell
Jon 
Jim 
Sally 
Jane 
Mary 

它可能不多,但它可能会帮助你取决于你想要达到的目标。