Fibonacci Sequence that deletes even numbers VBA - vba

Over the school holidays I was tasked with creating code that would output the Fibonacci sequence up to a certain number (in this case, the number I was given was 100000). Then, from that, I was ordered with deleting the cells that had even numbers, showing only cells that were odd. I have tried and tried many different method of doing both, but nothing seems to be working for me. Here is the code I was using:
Sub fib()
Dim x As Long
x = 100000
Range("A1") = 0
Range("A2") = 1
Do
If Range("A" & Range("A" & Rows.Count).End(xlUp).Row).Value + _
Range("A" & Range("A" & Rows.Count).End(xlUp).Row).Offset(-1, 0).Value >= x _
Then Exit Sub
Range("A" & Range("A" & Rows.Count).End(xlUp).Row).Offset(1, 0).FormulaR1C1 = _
"=R[-1]C+R[-2]C"
Loop
For Each Cell In Range("A1:A30")
If Cell.Row Mod 2 = 0 Then
Rows(Cell.Row).ClearContents
End If
Next
Selection.SpecialCells(xlCellTypeBlanks).Select
Selection.EntireRow.Delete
End Sub
Now, I understand there may be a few problems with my code. The main one I see is in the first block, where instead of just inputting the numbers in to the cell, it instead inputs the way it would be calculated (for example, cell A10's value is just given as =A9+A8). I am not sure if this would cause an error in the second part of the code, where it looks for cell values so it can delete whether it is even. Could I please have some assistance on this matter? It would be much appreciated, as I've been struggling with it for the past few days now. Any help is appreciated! :)

Try the code below.
Sub fib()
Dim x As Long
Dim lRow As Long
x = 100000
Range("A1") = 0
Range("A2") = 1
Do
If Range("A" & Range("A" & Rows.Count).End(xlUp).Row).Value + _
Range("A" & Range("A" & Rows.Count).End(xlUp).Row).Offset(-1, 0).Value >= x _
Then Exit Sub
Range("A" & Range("A" & Rows.Count).End(xlUp).Row).Offset(1, 0).FormulaR1C1 = _
"=R[-1]C+R[-2]C"
Columns("A:A").Select
Selection.Copy
Selection.PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks _
:=False, Transpose:=False
Loop
With ActiveSheet
lRow = WorksheetFunction.Max(Range("A65536").End(xlUp).Row)
For i = lRow To 2 Step -1
If .Cells(i, "A") Mod 2 = 0 Then
Rows(i).Delete
End If
Next i
End With
End Sub

Generate 30 values using formulas, then freeze those values (remove formulas), then remove any even values or values that exceed the max:
Sub fib()
Dim xMax As Long: xMax = 100000
Range("A1").Value = 0: Range("A2").Value = 1
With Range("A3:A30")
.Formula = "=A1+A2" ' generate using formula
.Value = .Value ' remove formulas and freeze values
End With
' now remove even values and values that exceed the xMax
' Remember to iterate backward when the loop involves deleting
Dim i As Long
For i = Cells(Rows.count, "A").End(xlUp).Row To 3 Step -1
If Cells(i, "A").Value Mod 2 = 0 Or _
Cells(i, "A").Value > xMax Then Rows(i).Delete
Next
End Sub

All this code seems fancier than it needs to be. Does this work?
The Do While..Loop builds your sequence cell by cell in column A up to 100,000.
The For Loop then runs through the list cell by cell and deletes even numbers.
Sub Fib()
Dim ws As Worksheet: Set ws = ThisWorkbook.Sheets(1)
Dim r As Long, x As Long, y As Long, z As Long, i As Long
Dim cell As Range
r = 1
x = 1
y = 0
z = 1
Do While z <= 100000
ws.Range("A" & r).Value = z
r = r + 1
z = x + y
y = x
x = z
Loop
For Each cell In ws.Range("A1", ws.Range("A1").End(xlDown))
If cell.Value Mod 2 = 0 Then cell.EntireRow.Delete
Next cell
End Sub

Related

Select 2 rows of data to cut, once cell containing "1" is found

Ok, so im a very basic user..
Im using the "If" function to find dips in data, when a dip is found column E shows "1", all others are "0". But I need that whole row with the "1" and the next row, even if it has a "0" or "1".
I currently have this:
If ActiveCell.Value = "1" Then
Selection.EntireRow.Cut
Sheets("Sheet2").Select
lMaxRows = Cells(Rows.Count, "A").End(xlUp).Row
Range("A" & lMaxRows + 1).Select
ActiveSheet.Paste
Sheets("Sheet1").Select
Else
So what I need is to tell it to select the row containing "1" (which it already does), as well as the next row.... the rest should cut and append the data to another worksheet.
Great post on alternatives and more reliable methods than ".Select". After reading, you can adjust your code. How to avoid using Select in Excel VBA
To answer your question, replace
Selection.EntireRow.Cut
with
Range(Selection.EntireRow, Selection.Offset(1, 0).EntireRow).Cut
This should get you a good start, you'll need to add some code to not cut all 5 rows above if some of the are blank because they've already been cut or you could remove blank rows on sheet 2 once this code is done.
Sub GetDipsData()
Dim i As Long
Dim c As Long
Dim LastConsecutiveDip As Long
Dim vLastRow As Long
Sheets("Sheet1").Activate
vLastRow = Cells(Rows.Count, "E").End(xlUp).Row
Application.ScreenUpdating = False
For i = 2 To vLastRow
If Cells(i, "E") = 1 Then
s2LastRow = Sheets("Sheet2").Cells(Rows.Count, "E").End(xlUp).Row
For c = i + 1 To vLastRow
If Cells(c, "E") = 1 Then
LastConsecutiveDip = c
Else
Exit For
End If
Next
If c <> i + 2 Then
'copy 5 above and 5 below
If i < 6 Then
Range(Rows(2), Rows(c).Offset(5, 0).EntireRow).Cut Sheets("Sheet2").Range("A" & s2LastRow)
ElseIf c + 5 > vLastRow Then
Range(Rows(i).Offset(-5, 0), Rows(vLastRow).EntireRow).Cut Sheets("Sheet2").Range("A" & s2LastRow)
Else
Range(Rows(i).Offset(-5, 0), Rows(c).Offset(5, 0).EntireRow).Cut Sheets("Sheet2").Range("A" & s2LastRow)
End If
i = c + 5
Else
'just copy 2 rows
If i + 1 > vLastRow Then
Rows(i).Cut Sheets("Sheet2").Range("A" & s2LastRow)
Else
Range(Rows(i), Rows(i).Offset(1, 0).EntireRow).Cut Sheets("Sheet2").Range("A" & s2LastRow)
i = i + 2
End If
End If
End If
Next
Application.ScreenUpdating = True
End Sub

Take the cell value and add that many rows below

I have an Excel sheet where I have different numbers in range A1 to A10. I need to take the value from the cell and add that many rows under that cell.
Lets say A1 as 3 as value and macro should add 2 rows below A1.
I have tried using "Rows" function but I couldn't find a way out.
Please help.
This should get you going. Let me know if you need any further help.
Sub CellsValue()
Dim Colm As Integer
Dim lastrow As Long, deflastrow As Long
'Get the Position of the Required column which has the numbers that it has to shift towards
Colm = WorksheetFunction.Match("Cells Value", Sheets("Sheet1").Rows(1), 0)
'Get the lastrow of that column
lastrow = ActiveSheet.Cells(Rows.Count, Colm).End(xlUp).Row
deflastrow = Application.Sum(Range(Cells(1, Colm), Cells(lastrow, Colm)))
For i = 2 To deflastrow + lastrow
Range("A" & i + 1).Select
InsertRow = Range("A" & i).Value
If InsertRow > 0 Then
InsertRow = InsertRow - 1
End If
If InsertRow = 0 Then
Range("A" & i + 1).Select
Else
For j = 1 To InsertRow
Selection.Insert Shift:=xlDown, CopyOrigin:=xlFormatFromLeftOrAbove
Next
End If
Next
End Sub
I have made the change. Now it will work. Kindly accept the answer if it works for you.
Alternate solution:
Sub tgr()
Dim ws As Worksheet
Dim i As Long
Const sCol As String = "A"
Set ws = ActiveWorkbook.ActiveSheet
For i = ws.Cells(ws.Rows.Count, sCol).End(xlUp).Row - 1 To 1 Step -1
With ws.Cells(i, sCol)
If IsNumeric(.Value) Then
If .Value - 1 > 0 Then .Offset(1).Resize(.Value - 1).EntireRow.Insert xlShiftDown
End If
End With
Next i
End Sub
Dim i, max, num As Integer
i = 1
max = 10
Do While i < max
Range("A" & i).Select
num = Selection.Value
Dim x As Integer
x = 0
Do While x < num
i = i + 1
Range("A" & i).Select
Selection.EntireRow.Insert
max = max + 1
x = x + 1
Loop
i = i + 1
Loop
End Sub

Copy row from one sheet to another

I want to copy data from one sheet to another with few conditions:
1. Start with row 1 and column 1 and match if the R1 C2 is not empty then copy the pair R1 C1 and R1 C2 and paste into the other sheet as a new row.
increment the counter for column and match R1 C1 with R1 C3 and so on.
increment the Row when the column counter reaches 10.
I tried the below code but gives compile error as Sub or function not defined.
Please help.
Private Sub CommandButton1_Click()
Dim x As Integer
Dim y As Integer
x = 2
y = 2
Do While Cells(x, 1) <> ""
If Cells(x, y) <> "" Then
Worksheets("Sheet1").Cells(x, 2).Copy
Worksheets("Sheet2").Activate
erow = Sheet2.Cells(Rows.Count, 1).End(xlUp) > Offset(1, 0).Row
ActiveSheet.Paste Destination:=Worksheets("Sheet2").Rows(erow)
End If
Worksheets("Sheet1").Activate
y = y + 1
If y = 10 Then x = x + 1
End If
Loop
End Sub
You are geting that error because of > in Sheet2.Cells(Rows.Count, 1).End(xlUp) > Offset(1, 0).Row
Avoid the use of using Integer when you are working with rows. Post excel2007, the row count has increased and the Integer may not be able to handle the row number.
Avoid the use of .Activate.
Is this what you are trying? (Untested)
Note: I am demonstrating and hence I am working with the excel cells directly. But in reality, I would be using autofilter & arrays to perform this operation.
Private Sub CommandButton1_Click()
Dim wsInput As Worksheet, wsOutput As Worksheet
Dim lRowInput As Long, lRowOutput As Long
Dim i As Long, j As Long
Set wsInput = ThisWorkbook.Worksheets("Sheet1")
Set wsOutput = ThisWorkbook.Worksheets("Sheet2")
With wsInput
lRowInput = .Range("A" & .Rows.Count).End(xlUp).Row
For i = 2 To lRowInput
If .Cells(i, 2).Value <> "" Then
For j = 3 To 10
lRowOutput = wsOutput.Range("A" & wsOutput.Rows.Count).End(xlUp).Row + 1
.Range(.Range(.Cells(i, 1), .Cells(i, 1)).Address & _
"," & _
.Range(.Cells(i, j), .Cells(i, j)).Address).Copy _
wsOutput.Range("A" & lRowOutput)
Next j
End If
Next i
End With
End Sub

Error 1004 when multiplying cell values based on criteria

I have a macro which looks at a range of cells. Every other cell is either a 1 or a 0 (sign bit). Depending on the sign bit, the next cell (a normal number) is multiplied either by 1 or 0. I keep getting a run time error 1004 Application-defined or object-defined error on the body of the ElseIf of the If statement (indicated below). Not sure what I'm doing wrong. My code is in a "proof-of-concept" stage so it's still pretty hackish.
Dim N As Long
------------------------------------------
Private Sub CommandButton1_Click()
Dim x As Integer
Dim y As Integer
x = 0
y = 1
N = Application.InputBox(Prompt:="Enter value", Type:=1)
If N > Columns.Count Then
N = Columns.Count
Else
For i = 4 To 9999
Cells(1, i).ClearContents
Cells(3, i).ClearContents
Next i
End If
For i = 4 To N + 3
x = x + y
Cells(1, i) = x
Next i
For i = 4 To N + 3
If Cells(2, i) = 1 Then
Cells(2, i).Offset(0, 1).Select = Cells(2, i).Offset(0, 1).Select * -1
ElseIf Cells(2, i) = 0 Then
'This is the line with errors vvvvvvvvvvvvvvvvv
Cells(2, i).Offset(0, 1).Select = Cells(2, i).Offset(0, 1).Select * 1
End If
Next i
End Sub
That's because you're using Select. Obviously, Select and Activate don't give you values. They select or activate the cell, not different from manually clicking on them using the mouse or moving/activating to them using the keyboard or what else. Multiplying them by a value is a major no-no.
The Range property you should be looking for is Value. In any case, I think you're making it difficult because of having two loops. You really should reconsider your design pattern. In any case, here's my approach (mine's vertical, but it seems like yours is horizontal, so be clear exactly what is on your end so this can be adjusted).
Private Sub CommandButton1_Click()
Dim WS As Worksheet
Dim LastRow As Long
Dim Iter As Long
Dim CurrCell As Range
Const Col = 1
With ThisWorkbook
Set WS = .Sheets("Sheet3") 'Change as necessary.
End With
With WS
LastRow = .Range("A" & .Rows.Count).End(xlUp).Row
For Iter = 1 To LastRow 'Change as necessary.
Set CurrCell = .Cells(Iter, Col)
Select Case CurrCell.Value
Case 1
CurrCell.Offset(0, 1).Value = (CurrCell.Offset(0, 1).Value * (-1))
Case 0
CurrCell.Offset(0, 1).Value = (CurrCell.Offset(0, 1).Value * 1) 'Is this even necessary? It's an identity.
End Select
Next
End With
End Sub
Screenshot:
Let us know if this helps.

Comparing and Updating 2 Different Worksheets

I need to compare 1 worksheet (Sheet1) to another similar worksheet (Sheet2)
Sheet2 contains up to date information,which needs to be transferred to Sheet1.
However, I've run into a couple of problems:
There are some rows in Sheet1 that are not Sheet2. These need to be ignored/skipped over
There are some rows in Sheet2 that are not Sheet1. These need to be appended to the end of Sheet1
If a row exists in both Sheets, the information from the row sheet 2 needs to be transferred to the corresponding row in Sheet1
For what its worth, they have same number of columns and the column titles are exactly the same.
I've tried using a dictionary object to accomplish this but am still having all sorts of trouble.
Here's the code I have tried thus far:
Sub createDictionary()
Dim dict1, dict2 As Object
Set dict1 = CreateObject("Scripting.Dictionary")
Set dict2 = CreateObject("Scripting.Dictionary")
Dim maxRows1, maxRows2 As Long
Dim i, ii, j, k As Integer
maxRows1 = Worksheets("Sheet1").Range("A65000").End(xlUp).Row
For i = 2 To maxRows1
Dim cell1 As String
cell1 = Worksheets("Sheet1").cells(i, 2).Text & " " & Worksheets("Sheet1").cells(i, 11).Text
If Not dict1.Exists(cell1) Then
dict1.Add cell1, cell1
End If
Next i
maxRows2 = Worksheets("Sheet2").Range("A65000").End(xlUp).Row
For ii = 2 To maxRows2
Dim cell2 As String
cell2 = Worksheets("Sheet2").cells(ii, 11).Text
If Not dict2.Exists(cell2) Then
dict2.Add cell2, cell2
End If
Next ii
Dim rngSearch1, rngFound1, rngSearch2, rngFound2 As Range
For j = 2 To maxRows1
Dim Sheet1Str, Sheet2Str As String
Sheet1Str = Worksheets("Sheet1").cells(j, 2).Text & " " & Worksheets("Sheet1").cells(j, 11).Text
Sheet2Str = Worksheets("Sheet2").cells(j, 11).Text
If dict2.Exists(Sheet1Str) = False Then
'ElseIf Not dict1.Exists(Sheet2) Then
'
' Worksheets("Sheet2").Range("A" & j & ":" & "Z" & j).Copy
' Worksheets("Sheet1").Range("A" & maxRows1 + 1).Insert
' Worksheets("Sheet1").Range("A" & maxRows1 + 1).Interior.Color = RGB(255, 255, 0)
' Worksheets("Sheet1").Range("U" & maxRows1 + 1) = "INCH"
' Worksheets("Sheet1").Range("Q" & maxRows1 + 1) = "FPM"
' Worksheets("Sheet1").Range("S" & maxRows1 + 1) = "INCHES WIDE"
' Worksheets("Sheet2").Range("K" & j) = Replace(Worksheets("Sheet2").Range("K" & j), Worksheets("Sheet2").Range("B" & j), "")
' Worksheets("Sheet1").Range("K" & maxRows1 + 1) = Trim(Worksheets("Sheet2").Range("K" & j))
Else
For k = 3 To 6
If Not k = 11 Then
If Not UCase(Worksheets("Sheet1").cells(j, k).Value) = UCase(Worksheets("Sheet2").cells(j, k).Value) Then
Worksheets("Sheet1").cells(j, k).Value = Worksheets("Sheet2").cells(j, k).Value
End If
End If
Next k
End If
Next j
End Sub
Cool question, and the "does row order matter" question above lends itself nicely to using Excel's built in Range.RemoveDuplicates method. Let's get into it...
Suppose Sheet1 looks like this:
Let's say Sheet2 looks like this:
All the conditions that are described in your original question are met here. Namely:
There are rows on Sheet1 that are not on Sheet2 (row 2, for example). These will be left alone.
There are rows on Sheet2 that are not on Sheet1 (row 2, for example). These will be added to Sheet1.
There are rows that are the same on Sheet2 and Sheet1, save for a single update. (Row 7 on Sheet2, for example.) These rows will be updated on Sheet1. Of course, your situation will be different -- perhaps more columns might be updated, or they might not be in column E like my example -- you'll need to do a bit of customization here.
The following heavily-commented script walks through copying data from Sheet2 to Sheet1, then letting Excel's built-in Range.RemoveDuplicates method kill all of the rows that have been updated in column E. The script also makes use of a couple handy functions: LastRowNum and LastColNum.
Option Explicit
Sub MergeSheetTwoIntoSheetOne()
Dim Range1 As Range, Range2 As Range
Dim LastRow1 As Long, LastRow2 As Long, _
LastCol As Long
'setup - set references up-front
LastRow2 = LastRowNum(Sheet2)
LastRow1 = LastRowNum(Sheet1)
LastCol = LastColNum(Sheet1) '<~ last col the same on both sheets
'setup - identify the data block on sheet 2
With Sheet2
Set Range2 = .Range(.Cells(2, 1), .Cells(LastRow2, LastCol))
End With
'setup - identify the data block on sheet 1
With Sheet1
Set Range1 = .Range(.Cells(2, 1), .Cells(LastRow1, LastCol))
End With
'step 1 - move the data block on sheet 1 down the sheet
' to allow room for the data block from sheet 2
Range1.Cut Destination:=Sheet1.Cells(LastRow2 + 1, 1)
'step 2 - move the data block from sheet 2 into the recently-
' cleared space on sheet 1
Range2.Copy Destination:=Sheet1.Cells(2, 1)
'step 3 - find the NEW last row on sheet 1
LastRow1 = LastRowNum(Sheet1)
'step 4 - use excel's built-in duplicate removal to
' kill all dupes on every column EXCEPT for those
' that might have been updated on sheet 2...
' in this example, Column E is where updates take place
With Sheet1
Set Range1 = .Range(.Cells(2, 1), .Cells(LastRow1, LastCol))
Range1.RemoveDuplicates Columns:=Array(1, 2, 3, 4), Header:=xlYes
End With
End Sub
'this handy function allows us to find the last row with a one-liner
Public Function LastRowNum(Sheet As Worksheet) As Long
If Application.WorksheetFunction.CountA(Sheet.Cells) <> 0 Then
LastRowNum = Sheet.Cells.Find(What:="*", _
LookIn:=xlFormulas, _
SearchOrder:=xlByRows, _
SearchDirection:=xlPrevious).Row
Else
LastRowNum = 1
End If
End Function
'this handy function allows us to find the last column with a one-liner
Public Function LastColNum(Sheet As Worksheet) As Long
If Application.WorksheetFunction.CountA(Sheet.Cells) <> 0 Then
LastColNum = Sheet.Cells.Find(What:="*", _
LookIn:=xlFormulas, _
SearchOrder:=xlByColumns, _
SearchDirection:=xlPrevious).Column
Else
LastColNum = 1
End If
End Function
Running this script results in the following: