简体   繁体   English

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

[英]How can I assign the SpecialCells of one range to a new range?

I know that I can accomplish this via iterating over the first range, but I'm curious to see if I can accomplish it using the SpecialCells property. 我知道我可以通过迭代第一个范围来完成这个,但我很想知道我是否可以使用SpecialCells属性来完成它。

Say I have a column of names with empty cells in between: 假设我有一列名称,中间有空单元格:

 A     B    C
Jon
Jim
Sally

Jane


Mary

If I want to use VBA to copy over just the used cells, I can say 如果我想使用VBA来复制已使用的单元格,我可以说

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

and end up with 并最终得到

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


Mary

Instead, I'd like to be able to do this without having to paste a range anywhere. 相反,我希望能够在不必在任何地方粘贴范围的情况下执行此操作。

What I want to be able to do is have a range containing [Jon,Jim,Sally,Jane,Mary] , but if I try Set rng = Range("A:A").SpecialCells(xlCellTypeConstants,xlTextValues) , I either end up with the spaces as elements of the range, or using a hard-coded range of cells, with one that counts only [Jon, Jim, Sally] before it hits the space. 我想要做的是有一个范围包含[Jon,Jim,Sally,Jane,Mary] ,但是如果我尝试Set rng = Range("A:A").SpecialCells(xlCellTypeConstants,xlTextValues) ,我要么最后将空格作为范围的元素,或使用硬编码范围的单元格,其中只有[Jon, Jim, Sally]才能进入空间。

I'd like to be able to use the range elsewhere in the code, and I think the SpecialCells is a nice compact way of doing it, but is my only alternative to do it in a loop and compare cells as <> "" ? 我希望能够在代码中的其他地方使用范围,我认为SpecialCells是一种很好的紧凑方式,但是我唯一的选择是在循环中进行并将单元格比作<> ""

Consider the following code 请考虑以下代码

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

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

The only reliable piece of information in the above is r.Cells.Count . 上面唯一可靠的信息是r.Cells.Count The Rows get cut at the first blank. Rows第一个空白处被切断。 I imagine this confuses the whole pasting process. 我想这会混淆整个粘贴过程。 So, you can't paste r directly to the worksheet. 因此,您无法将r直接粘贴到工作表中。

You could transfer it to a Variant array, and then slap* that onto the sheet. 您可以将其传输到Variant数组,然后将其打印到工作表上。 But how to do this? 但是怎么做呢? Well, r.Cells is akin to a collection. 好吧, r.Cells类似于一个系列。 Perhaps convert it to an array like this: 也许将它转换为这样的数组:

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

No need to check for empty cells. 无需检查空单元格。

You could also use Chip Pearson's CollectionToArray procedure , which is basically a fancier implementation of the above code, maybe with a bit of modification. 你也可以使用Chip Pearson的CollectionToArray程序 ,它基本上是上面代码的一个更好的实现,可能需要一些修改。

By the way, checking for <> "" will not reject cells whose value is an empty string "" . 顺便说一下,检查<> ""不会拒绝值为空字符串"" If you must check for truly empty/"blank" cells, then IsEmpty is safer. 如果必须检查真正的空/“空”单元格,那么IsEmpty更安全。

*Credits to @Issun for coining "slap" in this context. *在这种情况下,@ Issun致力于“打击”。

If you really want to just use the specialcells, you'll need to do a for each loop, but here's how to do it without a variant array or checking for empty cell. 如果你真的想要使用特殊的单元,你需要为每个循环做一个,但是这里是如何在没有变量数组或检查空单元格的情况下进行的。 Note that I am using a dictionary in reverse (see notes below) to store cells as items (not keys) so I can utilize the .Items method that spits out an array of all items in the dictionary. 请注意,我正在反向使用字典(请参阅下面的注释)将单元格存储为项目(而不是键),因此我可以使用.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

But there is a faster way to do this, in case you are working with a fairly big range. 但是有一种更快的方法可以做到这一点,以防你在相当大的范围内工作。 Use the dictionary object since it has the ability to spit out an array of all the keys/items inside it (which you can transpose to a range). 使用字典对象,因为它能够吐出其中的所有键/项的数组(您可以将其转置到范围)。 Collections do not have this abliity, but dictionaries only allow 1 of each key. 集合没有这种可靠性,但字典只允许每个密钥中的一个。 The work around? 工作? Use the dictionary in reverse, placing your values as items and a counter for keys! 反向使用字典,将值作为项目和键的计数器放置!

Here's an example of how to use the variant array/dictionary (with dupes allowed): 这是一个如何使用变量数组/字典(允许使用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

This is much faster than using special cells (since VBA handles the work without consulting Excel) and you can use transpose as if it were paste, so I prefer this method. 这比使用特殊单元格快得多 (因为VBA在不咨询Excel的情况下处理工作)并且您可以像使用粘贴一样使用转置,所以我更喜欢这种方法。

As JFC has noted, using a dictionary object doesn't really seem to have a lot of benifits, the biggest reason is that it's easy to transpose the array plus you can transpose it horizontally as well, which is very fun. 正如JFC所指出的那样,使用字典对象似乎并没有太多的好处,最大的原因是它可以很容易地转换数组,你也可以水平转置它,这非常有趣。

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

Since the Range object represents actual cells ( A1 , A2 , A3 , A5 and A8 in this case), I don't think you can compact in a 5-consecutive-cells Range without pasting it anywhere. 由于Range对象代表实际单元格(在这种情况下为A1A2A3A5A8 ),我认为你不能在5连续单元格范围内压缩而不将其粘贴到任何地方。

However, if you need to to loop on it, you don't need to use a comparison, using For Each will skip the blanks: 但是,如果你需要循环它,你不需要使用比较,使用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 

It's probably not much, but it may help you depending on what you want to achieve. 它可能并不多,但它可能会帮助你取决于你想要达到的目标。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM