Как я могу назначить SpecialCells одного диапазона на новый диапазон? - PullRequest
3 голосов
/ 23 августа 2011

Я знаю, что могу сделать это путем итерации по первому диапазону, но мне любопытно посмотреть, смогу ли я сделать это, используя свойство 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 - хороший компактный способ сделать это, но я - единственная альтернатива, чтобы сделать это в цикле и сравнить ячейки как <> ""

Ответы [ 3 ]

4 голосов
/ 23 августа 2011

Рассмотрим следующий код

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.Count.Rows обрезают на первом бланке.Я полагаю, что это смущает весь процесс вставки.Таким образом, вы не можете вставить 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

Нет необходимости проверять наличие пустых ячеек.

Вы также можете использовать процедуру CollectionToArray Чипа Пирсона , которая в основном является более изящной реализацией приведенного выше кода, возможно, с небольшой модификацией.

Кстати, проверка на <> "" не будет отклонять ячейки, значение которых является пустой строкой "".Если вы должны проверить наличие действительно пустых / «пустых» ячеек, то IsEmpty безопаснее.

* Кредиты @Issun для создания «пощечины» в этом контексте.

2 голосов
/ 23 августа 2011

Если вы действительно хотите просто использовать специальные ячейки, вам нужно сделать a для каждого цикла, но вот как это сделать без массива вариантов или проверки наличия пустой ячейки.Обратите внимание, что я использую словарь в обратном порядке (см. Примечания ниже) для хранения ячеек как элементов (не ключей), чтобы я мог использовать метод .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

Но есть более быстрый способ сделать это, если вы работаете с довольно большим диапазоном.Используйте объект словаря, так как он имеет возможность выплевывать массив всех ключей / элементов внутри него (которые вы можете транспонировать в диапазон).Коллекции не имеют этой возможности, но словари допускают только 1 из каждого ключа.Работа вокруг?Используйте словарь в обратном порядке, поместив ваши значения в качестве элементов и счетчик для ключей!

Вот пример того, как использовать вариантный массив / словарь (с разрешенными дубликатами):

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), и вы можете использовать transpose, как если бы это была вставка, поэтому я предпочитаю этот метод.

Поскольку JFC имеетСледует отметить, что использование словарного объекта на самом деле не имеет особых преимуществ, основная причина в том, что массив можно легко транспонировать, а также можно перемещать его по горизонтали, что очень забавно.

Sheet1.Range(Cells(1, 3), Cells(1, dict.Count + 2)).Value = _ 
Application.Transpose(Application.Transpose(dict.items)) 
1 голос
/ 23 августа 2011

Поскольку объект Range представляет фактические ячейки (A1, A2, A3, A5 и A8 в этом случае), я не думаю, что вы можете сжимать в 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 

Возможно, это немного, но это может помочь вам в зависимости от того, чего вы хотите достичь.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...