I seem to have a strange problem as some ghost values have entered my file. I got this file from someone but looks like file has seen several deletion, copy pastes etc. Please see attached image.
It shows ghost values in cell J186 and the values returned by various IS*** functions on cell j186. Such values are there in several columns in the file and I am sure they are consuming a lot of Filesize and the file is crashing every now and then. The file is 100 MB.
For example, when I select any cell in column L say Cell L56 and press Ctrl+Down, the cursor gets stuck in the cell L186 even when there is no value. If I select the cells L3:L186 and manually enter delete, something gets deleted (I cant see) and then the range functions as a normal range (i.e. If i select any random cell in that range and do a Ctrl+Down, it goes to the last row in Excel Row 1048576) Any cell in the range upto L186 shows the same behaviour as cell J186.
Is there a way to write a VBA code to identify such cells and clear contents of such cells?
Thanks in advance.
Yes, there is something strange here ..... zero length cells that are not actually blank (when tested with SpecialCells(xlBlank)
On your sample file =CODE(A117) returns #VALUE. Yet the cell is not blank
This array based code provides a very quick way of turning the cells to truely blank
Sub QuickReplace()
Dim rng1 As Range
Dim X
Dim lngRow As Long
Dim lngCol As Long
ActiveSheet.UsedRange
X = ActiveSheet.UsedRange.Value2
For lngRow = 1 To UBound(X, 1)
For lngCol = 1 To UBound(X, 2)
If Len(X(lngRow, lngCol)) = 0 Then X(lngRow, lngCol) = vbNullString
Next
Next
ActiveSheet.UsedRange.Value2 = X
End Sub
This code was successful. But the file size did not decrease much.
Sub cleancolumns()
Dim i As Integer
Dim j As Integer
Dim Rng As Range
j = 1
Do While j < 5010
Set Rng = Range(Cells(5, j), Cells(186, j))
If WorksheetFunction.Sum(Rng) = 0 Then
Rng.Select
Selection.ClearContents
j = j + 1
Else
j = j + 1
End If
Loop
ActiveWorkbook.Save
End Sub
There are a million cells in all, also counting the above ranges where full range is "". searching each cell one by one is very slow. Hence I did the above workaround.
The above code checks for the sum of the range and if the sum of the range is zero it is assumed to contain ""'s and clears contents. Else it skips the column and checks for the next column.
However, this does not remedy a situation where there are few genuine values and the rest are ""'s. These also have to be taken into account in a separate If statement i guess. That will make it very slow but doing this appears to be unavoidable.
Update based on Brettdj's response
The following variant of Brettdj's code worked. usedrange appeared to be larger than what my 6GB computer could handle. So I broke the data chunk by chunk to avoid "Out of memory" error. Also there were some error values which had to be removed before the Len function was applied. Now the file sizes have shrunk by a third (mainly by replacing 0's by blanks - there were too many). Thankfully the ghosts seem to have been busted.
Sub QuickReplace1()
Dim rng1 As Range
Dim X As Variant
Dim lngRow As Long
Dim lngCol As Long
' took no more than 500 columns at a time not to risk file crashing. Changed the values manually to clear chunk by chunk
Set rng1 = Range(Cells(1, 3501), Cells(7500, 4000))
X = rng1.Value2
For lngRow = 1 To UBound(X, 1)
For lngCol = 1 To UBound(X, 2)
If IsError(X(lngRow, lngCol)) Then X(lngRow, lngCol) = vbNullString
If X(lngRow, lngCol) = 0 Then X(lngRow, lngCol) = vbNullString
If Len(X(lngRow, lngCol)) = 0 Then X(lngRow, lngCol) = vbNullString
Next
Next
rng1.Value2 = X
End Sub
Related
Hello I need to advice some formulas on my problem:
How can I combine two, three or more columns into single one column?
And if in columns are "empty" cells I want to skip these cells inside of that single one column.
But be aware! This is the problem. All columns are contains another formulas. So these "empty" cells are in fact contains my another formulas with result ="".
Here is example of what I want to get - in column E:
EDIT:
New functions like TOCOL are not available in my Microsoft Office 365 MSO: 16.0.14326.21092 (32 bit).
You can use:
Formula in E2:
=TOCOL(IF(A2:C10="",NA(),A2:C10),3,1)
Note that just =TOCOL(A2:C10,3,1) is not going to cut it if these cells hold an empty string "".
If your data is not very huge use:
=FILTERXML("<t><s>"&TEXTJOIN("</s><s>",1,TRANSPOSE(A2:C10))&"</s></t>","//s")
With VBA:
Option Explicit
Sub To_Col()
Dim lngR As Long, lngC As Long, varV, lngRow As Long, lngCol As Long
varV = [A2:C10]
With ActiveCell
lngRow = .Row
lngCol = .Column
End With
For lngC = 1 To UBound(varV, 2)
For lngR = 1 To UBound(varV)
If varV(lngR, lngC) <> "" Then
Cells(lngRow, lngCol).Value = varV(lngR, lngC)
lngRow = lngRow + 1
End If
Next lngR
Next lngC
End Sub
place in E2 and launch macro, change [A2:C10] with your real range
I am attempting to run a VBA macro that iterates down about 67,000 rows with 100 columns in each row. For each of the cells in these rows, the value is compared against a column with 87 entries in another sheet. There are no errors noted when the code is run but Excel crashes every time. The odd thing is that the code seems to work; I have it set to mark each row in which a match is found and it does so before crashing. I have attempted to run it many times and it has gotten through between 800 and 11,000 rows before crashing, depending on the attempt.
My first suspect was memory overflow due to the volume of calculations but my system shows CPU utilization at 100% and memory usage around 50% while running this code:
Sub Verify()
Dim codes As String
Dim field As Object
For i = 2 To Sheets("DSaudit").Rows.Count
For Each field In Sheets("Dsaudit").Range(Cells(i, 12), Cells(i, 111))
r = 1
While r <= 87
codes = ThisWorkbook.Sheets("287 Denominator CPT").Cells(r, 1).Value
If field = codes Then
Cells(i, 112).Value = "True"
r = 88
Else
r = r + 1
End If
Wend
Next field
i = i + 1
Next i
End Sub
It should also be noted that I am still very new to VBA so it's likely I've made some sort of egregious rookie mistake. Can I make some alterations to this code to avoid a crash or should I scrap it and take a more efficient approach?
When ever possible iterate variant arrays. This limits the number of times vba needs to access the worksheet.
Every time the veil between vba and Excel is pierced cost time. This only pierces that veil 3 times not 9,031,385,088
Sub Verify()
With Sheets("DSaudit")
'Get last row of Data
Dim lastrow As Long
lastrow = .Cells(.Rows.Count, 12).End(xlUp).Row 'if column 12 ends before the last row of data change to column that has them all.
'Load Array with input Values
Dim rng As Variant
rng = .Range(.Cells(2, 12), .Cells(lastrow, 111)).Value
'Create output array
Dim outpt As Variant
ReDim outpt(1 To UBound(rng, 1), 1 To 1)
'Create Match array
Dim mtch As Variant
mtch = Worksheets("287 Denominator CPT").Range("A1:A87").Value
'Loop through first dimension(Row)
Dim i As Long
For i = LBound(rng, 1) To UBound(rng, 1)
'Loop second dimension(Column)
Dim j As Long
For j = LBound(rng, 2) To UBound(rng, 2)
'Loop Match array
Dim k As Long
For k = LBound(mtch, 1) To UBound(mtch, 1)
'If eqaul set value in output and exit the inner loop
If mtch(k, 1) = rng(i, j) Then
outpt(i, 1) = "True"
Exit For
End If
Next k
'If filled true then exit this for
If outpt(i, 1) = "True" Then Exit For
Next j
Next i
'Assign the values to the cells.
.Cells(2, 112).Resize(UBound(outpt, 1), 1).Value = outpt
End With
End Sub
I've been looking through the website and have not found a similar situation yet. Specifically, what I'm looking to do is the following.
Using the table with three columns,
Number Priority Age
1234567890 Low 1
1234567890 Low 2
1234567890 High 3
1234567890 High 4
I would like a VBA macro that will first copy the oldest record (determined by the age column), send it over to the current sheet, then delete that record from the main sheet, followed by saving the Excel file.
Again, I have not found anything near this just yet since all the ones I've seen copy ALL rows instead of specifics.
Any help would be amazing!
Edit: Here's the VBA code I tried using but I keep getting the same results (all rows being copied).
code
Sub MyMacro()
Dim i As Long, iMatches As Long
Dim aTokens() As String: aTokens = Split("10", ",")
For Each cell In Sheets("master").Range("A:A")
If (Len(cell.Value) = 0) Then Exit For
For i = 0 To UBound(aTokens)
If InStr(1, cell.Value, aTokens(i), vbTextCompare) Then
iMatches = (iMatches + 1)
Sheets("master").Rows(cell.Row).Copy Sheets("top10").Rows(iMatches)
End If
Next
Next
End Sub
code
Assuming this just wanted to be runned once, this will work. Not sure why you are using arrays. Your table have 3 columns, but you are saying two! Anyway this is working on your table.
Sub Move_Oldest()
Dim Rng As Range
Dim Lrow As Long
Dim Trow as long
Lrow = Sheets("top10").Range("a1000000").End(xlUp).Row
With Sheets("master")
Set Rng = Intersect(.UsedRange, .Columns(3))
If Not Rng Is Nothing Then
trow = Application.Match(Application.Max(Rng), Rng, 0)
.Cells(trow, 1).Resize(, 3).Copy Sheets("top10").Cells(Lrow + 1, 1)
.rows(trow).delete
End If
End With
End Sub
I want make this basic function of "copy&paste-values-on-a-new-row-each-time" run as fast as possible since the macro repeats the calculations hundreds of thousands of times. I just can't find the exact answer after searching this forum for ages.
Currently, I'm copying output numbers from a fixed range and, elsewhere on the worksheet, pasting the values on a new row for each new set of results.
Here's the portion of the code doing this:
Row = Row +1
Range("g15:ax15").copy
Range("ea18").select
ActiveCell.Offset(Row,0).select
Selection.PasteSpecial Paste:=xlPasteValues
Now from what I have found on this forum, I can replace the Copy/Paste functions completely with Range(destination).value = Range(results).value to speed things up. However, I can't figure out how to do this if the destination rows need to be offset by 1 each time. Also, I've read that one could even do away with "select" to speed things up further! How?
There are a number of options:
//This uses the `Destination` key word
Sub CopyAndPaste()
Dim i as long
For i = 1 to 10
Range("g15:ax15").Copy Destination:=Range("ea18").Offset(i, 0)
next i
End Sub
//If you need `PasteSpecial` then you cannot use `Destination` hence this version
Sub CopyAndPaste()
Dim i as long
For i = 1 to 10
Range("g15:ax15").Copy
Range("ea18").Offset(i, 0).PasteSpecial Paste:=xlPasteValues
next i
End Sub
Sometimes reading values into an array first and then writing back to the spreadsheet is quicker. Here is an example:
Sub CopyAndPaste()
Dim i As Long, numbers As Variant, rw As Long
numbers = Range("g15:ax15")
rw = 18
For i = 1 To 10
rw = rw + 1
Range(Cells(rw, 131), Cells(rw, 131 + UBound(numbers, 2) - 1)) = numbers
Next i
End Sub
You can do it without copying as yo mention (using a variant array as you are copying values only, not formats)
X = Range("g15:ax15").Value2
[ea18].Offset(1, 0).Resize(UBound(X, 1), UBound(X, 2)).Value2 = X
or with your variable offset
Dim lngCnt As Long
lngCnt = lngCnt + 1
X = Range("g15:ax15").Value2
[ea18].Offset(lngCnt, 0).Resize(UBound(X, 1), UBound(X, 2)).Value2 = X
Row = Row +1
Range("g15:ax15").copy
Range("ea18").Offset(Row,0).PasteSpecial Paste:=xlPasteValues
Select is a more-or-less useless method inherited from recordings.
I am currently using a lot of For ... Each loops in my code which is slowing it down a lot, is there a faster approach?
I have heard I could copy the range to an array and edit the array and paste it back but im having a few problems with editing each cell in the array.
Here is the current for each code I am using - Thanks.
Dim cell As Range
For Each cell In Sheets("sheet1").UsedRange
cell.Value = cell.Value
Next cell
Try this - MUCH faster and more efficient:
Sheets("sheet1").UsedRange.Value = Sheets("sheet1").UsedRange.Value
Something along these lines:
Dim aCells As Variant
Dim x As Long
Dim y As Long
aCells = Sheets("Sheet1").UsedRange
' Now do something with the array;
' We'll debug.print the contents of each element
' to verify that it matches the cells in the sheet
For x = 1 To UBound(aCells, 1)
For y = 1 To UBound(aCells, 2)
Debug.Print aCells(x, y)
Next
Next