powered by simpleCommunicator - 2.0.39     © 2025 Programmizd 02
Форумы / Microsoft Office [игнор отключен] [закрыт для гостей] / оптимизация замены пустых ячеек на 0 (Excel)
17 сообщений из 17, страница 1 из 1
оптимизация замены пустых ячеек на 0 (Excel)
    #38738715
l-freeman
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
добрый день
вот настряпал цикл на проверку и замену пустых значений в рабочем диапазоне на 0
но цикл отрабатывает сравнительно долго(таблица 58 столбцов и 5800 строк):


Set MyWo = DAOEx.Workbooks.Open("Workbook_sourse")
Slist = "list_sourse"

Frow = MyWo.Sheets(Slist).UsedRange.Row
Fcolumn = MyWo.Sheets(Slist).UsedRange.Column
Lrow = MyWo.Sheets(Slist).Cells(Frow, Fcolumn).End(xlDown).Row
Lcolumn = MyWo.Sheets(Slist).Cells(Frow, Fcolumn).End(xlEnd).Column

For y = Fcolumn To Lcolumn
For i = Frow To Lrow
If MyWo.Sheets(Slist).Cells(i, y).Value = Empty Then MyWo.Sheets(Slist).Cells(i, y) = 0
Next i
Next y

с оптимизацией как то напряг, в голову приходит только метод с Find, но очень сомневаюсь что он будет работать быстрее
помогите плз)
...
Рейтинг: 0 / 0
оптимизация замены пустых ячеек на 0 (Excel)
    #38738802
Maxim12345678
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
l-freemanв голову приходит только метод с Find, но очень сомневаюсь что он будет работать быстрее
помогите плз)
А Вы попробовали? А долго это сколько? Сколько по времени он меняет значения, если просто Ctrl+H?
Можно еще попробовать прогонять через:

Код: vbnet
1.
2.
3.
4.
5.
Dim RR as Range
For Each RR in Range("A1:Z58000")
'===
Next RR
               



Этот перебор должен быстрее работать.
...
Рейтинг: 0 / 0
оптимизация замены пустых ячеек на 0 (Excel)
    #38739162
Фотография The_Prist
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Maxim12345678Этот перебор должен быстрее работатьВ общем-то вряд ли, т.к. львиную долю времени забирает именно обращение к каждой ячейке. А как это будет происходить по большому счету в данном случае неважно. Выигрыш в скорости будет минимален. А вот если проходить по массиву, а к ячейкам обращать исключительно по необходимости - здесь уже можно выиграть скорость. А если при этом не сразу менять, а сначала в отдельный объект через Union - вообще быстро будет:
Код: vbnet
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
Sub test()
    Dim Frow As Long, Fcolumn As Long, Lrow As Long, Lcolumn As Long
    Dim MyWo As Object, Slist As String
    Set MyWo = DAOEx.Workbooks.Open("Workbook_sourse")
    Slist = "list_sourse"

    With MyWo.Sheets(Slist)
        Frow = .UsedRange.Row
        Fcolumn = .UsedRange.Column
        Lrow = .UsedRange.Row + .UsedRange.Rows.Count - 1
        Lcolumn = .UsedRange.Column + .UsedRange.Columns.Count - 1
        Dim rR As Range, vR, lr As Long, lc As Long

        vR = .Range(.Cells(1, 1), .Cells(Lrow, Lcolumn)).Value
        If Not IsArray(vR) Then ReDim vR(1 To 1, 1 To 1): vR(1, 1) = .Cells(Frow, Fcolumn).Value

        For lr = Frow To UBound(vR, 1)
            For lc = Fcolumn To UBound(vR, 2)
                If Len(vR(lr, lc)) = 0 Then
                    If rR Is Nothing Then
                        Set rR = .Cells(lr, lc)
                    Else
                        Set rR = Union(rR, .Cells(lr, lc))
                    End If
                End If
            Next lc
        Next lr
        If Not rR Is Nothing Then rR.Value = 0
    End With
End Sub



P.S. Заменил Ваше чудное определение последней строки и столбца. Если лист пустой или содержит лишь одну строку - получится ой как нехорошо - весь лист нулями заполнять...
Почитайте на досуге: Как определить последнюю ячейку на листе через VBA?
...
Рейтинг: 0 / 0
оптимизация замены пустых ячеек на 0 (Excel)
    #38740819
l-freeman
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Maxim12345678,
изменил на:
For Each acc In Range(Cells(Frow, Fcolumn), Cells(Lrow, Lcolumn))
If acc = Empty Then Cells(acc.Row, acc.Column) = 0
Next acc

вот только теперь не знаю как записать в ячейку на шаге acc нужное мне значения
Cells(acc.Row, acc.Column) - не работает, та в принципе думаю и не должно было бы)
...
Рейтинг: 0 / 0
оптимизация замены пустых ячеек на 0 (Excel)
    #38740822
l-freeman
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
The_Prist,

спасибо
...
Рейтинг: 0 / 0
оптимизация замены пустых ячеек на 0 (Excel)
    #38740907
l-freeman
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
l-freemanCells(acc.Row, acc.Column) - не работает, та в принципе думаю и не должно было бы)
Cells(acc.Row, acc.Column).value - работает, но как сказал тов. Прист, выигрыш во времени не заметен

а код тов.Приста конечно для меня, ламера, сложноват
он конечно работает, но я не понимаю некоторых моментов
...
Рейтинг: 0 / 0
оптимизация замены пустых ячеек на 0 (Excel)
    #38741060
Фотография ПЕНСИОНЕРКА
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
l-freeman,

Код: vbnet
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
Sub e140907()
Dim ws As Worksheet, Slist
Dim vr, dt1, y, i
Dim fcolumn As Long, Lcolumn As Long, frow As Long, Lrow As Long
'Set MyWo = DAOEx.Workbooks.Open("Workbook_sourse")
'Slist = "list_sourse"
Slist = "лист3"
''''''''''''''''''''''''''''''''''''''''''''''''''
''может вынесете обращение в листу----в ссылку----
''''''''''''''''''''''''''''''''''''''''''''''''''
Set ws = Sheets(Slist)
'frow = MyWo.Sheets(Slist).UsedRange.Row
'fcolumn = MyWo.Sheets(Slist).UsedRange.Column
'Lrow = MyWo.Sheets(Slist).Cells(frow, fcolumn).End(xlDown).Row

fcolumn = 1
Lcolumn = 58

frow = 1
Lrow = 20000

dt1 = Timer

'lcolumn = MyWo.Sheets(Slist).Cells(frow, fcolumn).End(xlEnd).Column
vr = ws.Range(ws.Cells(1, 1), ws.Cells(Lrow, Lcolumn)).Value

For y = fcolumn To Lcolumn
For i = frow To Lrow
If Len("" & vr(i, y)) = 0 Then ws.Cells(i, y) = 0
Next i
Next y
Debug.Print (Timer - dt1)


End Sub
...
Рейтинг: 0 / 0
оптимизация замены пустых ячеек на 0 (Excel)
    #38741187
Dmitri Krizhanovski
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Прошу прощения, что вмешиваюсь.

А вам не кажется, что простая замена будет работать быстрее приведенных алгоритмов?
Код: vbnet
1.
2.
3.
4.
5.
6.
7.
Sub RepalceEmptyWithZeroInternal(rng As Range)
    
    rng.Replace What:="", Replacement:="0", LookAt:=xlPart, _
        SearchOrder:=xlByRows, MatchCase:=False, SearchFormat:=False, _
        ReplaceFormat:=False

End Sub


А специальная вставка будет еще быстрее работать?
Код: vbnet
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
Sub ReplaceEmptyWithZero(rng As Range)

    Dim sh As Worksheet

    Set sh = ActiveWorkbook.Sheets.Add

    rng.Copy
    sh.Range("A1").PasteSpecial

    rng.Value = 0

    sh.Range(sh.Cells(1, 1), sh.Cells(rng.Rows.Count, rng.Columns.Count)).Copy

    rng.PasteSpecial Paste:=xlPasteAll, Operation:=xlNone, SkipBlanks:=True, Transpose:=False

    Application.DisplayAlerts = False
    sh.Delete
    Application.DisplayAlerts = True

    Set sh = rng.Parent
    sh.Select

End Sub



Книгу для теста прилагаю.
...
Рейтинг: 0 / 0
оптимизация замены пустых ячеек на 0 (Excel)
    #38741568
Фотография The_Prist
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Dmitri Krizhanovski,

1. Замена не заменит пустые ячейки, в которых пусто(Empty), а не строка нулевой длины. И работает нестабильно. Плюс, если в ячейке нечто вроде формулы: ="", то замена опять не сработает.
2. Ячейки со строкой нулевой длины останутся "пустыми", т.е. там так и останется строка нулевой длины. Плюс при Вашем подходе к спец.вставке есть большой шанс, что поедут формулы. Поэтому вставлять тогда уж надо Paste:=xlPasteValues. Формулы все равно вряд ли нужны, т.к. лист готовят к выгрузке в БД.
...
Рейтинг: 0 / 0
оптимизация замены пустых ячеек на 0 (Excel)
    #38937725
Bobgos
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Dmitri Krizhanovski,

Не пойму зачем гонять объекты cells и проверять их значения. Ведь можно
Код: vbnet
1.
2.
3.
4.
5.
Set rt=range(a1:z1000)
VArr= rt
// проверка значений 
//и формула, возвращающая строку нулевой длины и пустые ячейки вернут при vba.cbyte(varr(i,j) ноль
Rt=varr
...
Рейтинг: 0 / 0
оптимизация замены пустых ячеек на 0 (Excel)
    #38937873
anvg
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Доброе время суток
По мотивам Bobgos , естественно пологая, что реальные данные по структуре соответствуют примеру.
Код: vbnet
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
Public Sub changeToZero()
    Dim irow As Long, icol As Long, vData As Variant
    vData = ActiveSheet.UsedRange.Value
    For irow = 1 To UBound(vData, 1)
        For icol = 1 To UBound(vData, 2)
            vData(irow, icol) = CLng(vData(irow, icol))
        Next
    Next
    ActiveSheet.UsedRange.Value = vData
End Sub
...
Рейтинг: 0 / 0
оптимизация замены пустых ячеек на 0 (Excel)
    #38937875
booby
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
l-freeman,

скачал книгу, выложенную Dmitri Krizhanovski для экспериментов.

запустил ваш код, поправленный до такого вида:
Код: vbnet
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
Sub i_freeman_0()
Dim MyWo As Workbook
Dim Slist$
Dim Frow&, Fcolumn&, Lrow&, Lcolumn&, y&, i&
'Set MyWo = DAOEx.Workbooks.Open("Workbook_sourse")
Set MyWo = ThisWorkbook
Slist = "test" '"list_sourse"

'-----------------------------------
With MyWo.Sheets(Slist)
        Frow = .UsedRange.Row
        Fcolumn = .UsedRange.Column
        Lrow = .UsedRange.Row + .UsedRange.Rows.Count - 1
        Lcolumn = .UsedRange.Column + .UsedRange.Columns.Count - 1
End With
'------------------------------------
Dim tt#
tt = Timer

For y = Fcolumn To Lcolumn
For i = Frow To Lrow
If MyWo.Sheets(Slist).Cells(i, y).Value = Empty Then MyWo.Sheets(Slist).Cells(i, y) = 0
Next i
Next y

Debug.Print "i_freeman_0", (Timer - tt)

End Sub



время работы на моем стареньком компьютере - 20.6 секунды

в выложенном примере задействован диапазон в 84 * 5708 = 479472
Чтобы только добраться до value с целью сравнения вы сначала 479472 говорите:
(на каждом шаге!!!)
Эксель, в книге MyWo найди лист с именем slist и на нем отыщи клетку с координатами i,y

У вас просто нет права рассчитывать на быстрое выполнение.
Хотите скорости - научитесь выражаться короче.
ваша попытка
Код: vbnet
1.
2.
3.
For Each acc In Range(Cells(Frow, Fcolumn), Cells(Lrow, Lcolumn))
If acc = Empty Then Cells(acc.Row, acc.Column) = 0
Next acc



не просто неудачна, если она работает, то работает у вас случайно. Т.к. отношение имеет не к тому листу, который вы slist назвали, а к тому, в который сейчас глазками смотрите.

При этом это хуже первоначального варианта.
Там вы хоть точно знаете в какой книге искать.

А здесь вам не понравилось, что excel слишком быстро считает и вы решили наказать его за это, приказывая строкой Cells(acc.Row, acc.Column) = 0 следующее.

Эксель, всякий раз, когда найдешь в цикле обработки пустую клетку, определи,
в какой книге находится текущий лист, который я вижу глазами.

На этом листе найди клетку с координатами такими же, какие у текущей клетки
в цикле обработки (мы помним - откуда взятой - взятой из книги MyWo с листа slist), и в эту клетку (той книги, страницу которой я вижу глазами) запиши ноль.

Вы какого уроста ожидаете, если просите сделать работы больше, чем в своем первоначальном варианте? При этом не просто больше, а близко не то-же самое по смыслу.

Это издевательство какое-то, ничем не прикрытое. Толстый троллинг безответного экселя.

Начинаем сначала. Хотите скорости - научитесь разговаривать коротко.
Складываем "по складам":
клетки занятого диапазона листа slist книги MyWo == MyWo.Sheets(Slist).UsedRange

Для каждой клетки == For Each rr

Все вместе слитно: == For Each rr In MyWo.Sheets(Slist).UsedRange

Вот код, который должен у вас получиться.
Код: vbnet
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
Dim MyWo As Workbook
Dim Slist$

Set MyWo = DAOEx.Workbooks.Open("Workbook_sourse")
Slist = "list_sourse"

Dim rr As Range
Dim tt#
tt = Timer
'----------------------------
For Each rr In MyWo.Sheets(Slist).UsedRange
  If IsEmpty(rr) Then rr.Value2 = 0
Next
Debug.Print "test_1_0", (Timer - tt)



Этот вариант у меня отрабатывает за 7 секунд против первоначальных 20.6

Еще немного (около секунды на выложенном примере) можно сэкономить при выключении автоматического пересчета и обновления экрана.
В данном случае немного, т.к. доля обновляемых клеток в примере невелика.

Вариант, который предложил Bobgos отработает быстрее.
Но на больших объемах данных им следует пользоваться с некоторой осмотрительностью.
И помнить, что он критичнее по отношению к отключению пересчета и обновлению экрана, т.к. обновляется весь массив данных, а не некоторые клетки (предположительно - меньшинство).
такой вариант

Код: vbnet
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
Dim MyWo As Workbook
Dim Slist$

Set MyWo = DAOEx.Workbooks.Open("Workbook_sourse")
Slist = "list_sourse"

Dim rr As Range

Dim tt#
tt = Timer
'----------------------------
Dim v As Variant
Dim oldCalc

With Application
  .ScreenUpdating = False
  oldCalc = .Calculation
 .Calculation = xlCalculationManual
End With

Set rr = MyWo.Sheets(Slist).UsedRange

v = rr.Value2

Dim iRow&, iCol&

For iRow = LBound(v, 1) To UBound(v, 1)
  For iCol = LBound(v, 2) To UBound(v, 2)
    If IsEmpty(v(iRow, iCol)) Then v(iRow, iCol) = 0
  Next
Next

rr.Value2 = v

With Application
  .ScreenUpdating = True
  .Calculation = oldCalc
End With

Debug.Print "test_2", (Timer - tt)



на примере от Dmitri Krizhanovski
у меня отработал за 1.6 сек.
...
Рейтинг: 0 / 0
оптимизация замены пустых ячеек на 0 (Excel)
    #38938681
Bobgos
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
booby,
вау!!!
все по полочкам. Красавец!

1. интересно мнение экспертов - если перед вводом в массив диапазона еще и отсортировать диапазон?
например: поможет или навредит экселевская сортировка листа по столбцу (а лучше расширенная по... скажем 3-м столбцам), в котором опять же экселевской функцией (не vba) будет найдено максимальное количество пустых значений.
При этом если будет 10000 строк и всего 10 пустых значений то не придется перебирать все 10000.


2. подозрение есть, что манипуляции с .screenupdating и .Calculation значительно меньше влияют на скорость в последнем Варианте -1,6сек.. Пересчет в обоих случаях производится один раз при включении .Calculation или при присвоению диапазону значений массива v.
Поправьте пожалуйста, если ошибаюсь.
...
Рейтинг: 0 / 0
оптимизация замены пустых ячеек на 0 (Excel)
    #38938996
Казанский
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Bobgos1. интересно мнение экспертов - если перед вводом в массив диапазона еще и отсортировать диапазон?
... При этом если будет 10000 строк и всего 10 пустых значений то не придется перебирать все 10000.
Конечно, если отсортировать диапазон так, чтобы пустые значения образовали как можно меньшее количество областей, то выгоднее будет пробежаться по областям:
Код: vbnet
1.
2.
3.
4.
Dim r As Range
For Each r In ActiveSheet.UsedRange.SpecialCells(xlCellTypeBlanks).Areas
  r.Value = 0
Next

Однако при слишком большом числе областей (как в приложенном файле) метод SpecialCells дает сбой и возвращает весь диапазон, и весь он обнуляется :(
Так по крайней мере в Excel 2007, может в более поздних поправили.
Bobgos2. подозрение есть, что манипуляции с .screenupdating и .Calculation значительно меньше влияют на скорость в последнем Варианте -1,6сек.. Пересчет в обоих случаях производится один раз при включении .Calculation или при присвоению диапазону значений массива v.
Поправьте пожалуйста, если ошибаюсь.Верно.
Есть еще способ с вычислением формулы листа:
Код: vbnet
1.
2.
3.
4.
5.
6.
7.
8.
9.
Sub bb2()
Dim t!, r As Range, a$

t = Timer
Set r = ActiveSheet.UsedRange
a = r.Address(, , Application.ReferenceStyle)
r.Value = Evaluate(a & "+0")
Debug.Print Timer - t
End Sub

По моим замерам, скорость такая же, как при работе с массивом - 2,2с.
Если в диапазоне могут быть нечисловые значения, придется использовать более сложную формулу
Код: vbnet
1.
r.Value = Evaluate(Replace("IF(ISBLANK(~),0,~)", "~", a))

и результат 2,5-2,6с.
...
Рейтинг: 0 / 0
оптимизация замены пустых ячеек на 0 (Excel)
    #38939030
Казанский
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
А самый быстрый способ - PasteSpecial, но не как предложил Dmitri Krizhanovski, а скопировать ячейку с 0 и задать операцию сложения. При этом нечисловые значения игнорируются, числовые, очевидно, не меняются, к формулам, возвращающим число, дописывается "+0", пустые становятся 0:
Код: vbnet
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
Sub bb3()
Dim t!, r As Range, c As Range

t = Timer
Set r = ActiveSheet.UsedRange
Set c = r(r.Count).Offset(2)  'пустая ячейка
c = 0
c.Copy
r.PasteSpecial xlPasteValues, xlPasteSpecialOperationAdd
c.ClearContents               'очистить обратно
'Application.CutCopyMode = False 'необязательно
Debug.Print Timer - t
End Sub

Мой результат 0,28с .
...
Рейтинг: 0 / 0
оптимизация замены пустых ячеек на 0 (Excel)
    #38939663
Bobgos
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
КазанскийА самый быстрый способ - PasteSpecial, но не как предложил Dmitri Krizhanovski, а скопировать ячейку с 0 и задать операцию сложения. При этом нечисловые значения игнорируются, числовые, очевидно, не меняются, к формулам, возвращающим число, дописывается "+0", пустые становятся 0:

Мой результат 0,28с .
the best
...
Рейтинг: 0 / 0
оптимизация замены пустых ячеек на 0 (Excel)
    #38939955
booby
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Bobgos,

авторthe best
- опять антоновка?

(
Сидит Ньютон под деревом. На Ньютона падает яблоко.
Вдруг, разверзлась Земля, из земли выперла Жопа, и яблоко исчезло в недрах ея.
- Что это было? - отдает в пространство вопрос Ньютон.
Вдруг, опять разверзлась Земля, из Земли выперла Жопа, и прозвучало:
- Антоновка!
)
...
Рейтинг: 0 / 0
17 сообщений из 17, страница 1 из 1
Форумы / Microsoft Office [игнор отключен] [закрыт для гостей] / оптимизация замены пустых ячеек на 0 (Excel)
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]