How can I make this function iterate through both of ranges? - excel

So I have been trying to build a function to increment the cells using a For loop
=IFERROR(IF(AND(N$10>=PivotTabel!$L5;N$10<=PivotTabel!$M5);"1";"0.5");"X") &
IF(AND(N$10>=Sheet1!$L125;N$10<=Sheet1!$M125);"yes";"n") &
IF(AND(N$10>=Sheet1!$L126;N$10<=Sheet1!$M126);"yes";"n") &
IF(AND(N$10>=Sheet1!$L127;N$10<=Sheet1!$M127);"yes";"n")
This formula is to check if a date is between a date period ( for example to check if 01.01.2020 is between 02.08.2019 and 20.02.2020 if True in the first case i print "1" and other cases i print "yes").
As you can see above is the formula that i need to write in VBA to iterate through a specified number of cells which are $L125:$L139 for one column, and the other column $M125:$M139
I wrote the function below but it gives me #VALUE!
Function Date_Increment(MaxCount As Integer) As String
' This function does incrementation of date ranges
Dim Result As String
Static i As Integer
i = 125
Dim cell As Range
'MaxCount is the number times to iterate just to test
'My idea is to use the function COUNT("L125:L139") to return the number of cells that are not blank
For Each i In MaxCount
' this is the cell i want to run formula in
Range("GUI!D12").Formula = "=IFERROR(IF(AND(D$10>=PivotTabel!$L5;D$10<=PivotTabel!$M5);""1"";""0.5"");""X"") & IF(AND(D$10>=Sheet1!$L" & i & ";D$10<=Sheet1!$M" & i & ");""yes"";""n"")"
Result = Range("GUI!D12").Formula
i = i + 1
Next cell
'Next j
DateRange_Increment
End Function
My question is : How can I make this function iterate through both of ranges? Or If there is a simple solutions using only formulas i would also use it. In addition please check if i have errors in the function.
Any help i would really appreciate it.

Related

Formula to verify row values and retrieve columns

I have a table in Excel as shown in the attached image (Until Column F) and would like to see the final column "Result":
ExcelData:
The Result column should retrieve Column Names where the row values is "IF".
I can use the IF function in Excel, but that would be a long statement that I would have to write to retrieve the final output if there are like 20 columns that I would have to check.
If you are okay with creating a UDF (User Defined Function), then you can essentially create your own worksheet function to do this.
In this function, you will do a quick loop in the input range, and check if any cell in that range is equal to "IF". If so, you will strip the column letter out of the .Address property.
Public Function getIFCols(ByVal rng As Range) As String
Dim retVal As String, cel As Range
For Each cel In rng.Cells
If cel.Value = "IF" Then
retVal = Trim(retVal & " " & colLtr(cel))
End If
Next
getIFCols = Replace(retVal, " ", ", ")
End Function
Private Function colLtr(colRng As Range) As String
colLtr = Split(colRng.Address, "$")(1)
End Function
You will call this function as such:
=getIFCols(B1:F1)
The great thing about this function is that it doesn't require a set amount of columns. So if you need 3 columns checked on one row and 10 on another, it's pretty dynamic.
For Excel Online you can try the texjoin
=TEXTJOIN(",",TRUE,IF(B2:G2="IF",$B$1:$G$1,""))

Use CELL on an array to return string made of types of the cells

Lets say we have 5000 rows with random values (blanks, numbers, characters). I need to show type of all the cells in these 5000 rows in a single cell using a formula. Is it actually possible? I've tried to CONCATENATE(CELL("type";array)) and ctrl+shift+enter but it didn't work (it returns the type of the first cell in the array).
If you want to know, this is for finding a cell with text rather than values or blanks in a very big file. Maybe you have a better solution.
Thanks in advance.
UPD: thanks for macros but I can't use them in this workbook, I need a formula-solution.
UPD: I've got how to do it with conditional formatting => new rule => use a formula to determine... => use ISTEXT('first cell of the range') formula
But still, is it possible to create the formula?
The best way to go about this is to use MACROs
Here is my sample code:
Sub Button2_Click()
numRows = 10 ' Number fo rows to loop through, in your case 5000
'loop through each cell located in column 1
'Check its type
'Concatenate each one in 1 cell on the 8th column
For i = 1 To numRows
Sheet1.Cells(1, 8).Value = Sheet1.Cells(1, 8).Value & TypeName(Sheet1.Cells(i, 1).Value) & ","
Next i
End Sub
You can adapt this small user defined function to your needs.
Say we are looking at cells in the first row, from A1 through D1 and we want to concatenate their types into a single cell. Enter the following UDF() in a standard module:
Public Function KonKaType(rIN As Range) As String
Dim r As Range
For Each r In rIN
s = "cell(""type""," & r.Address(0, 0) & ")"
KonKaType = KonKaType & Evaluate(s)
Next r
End Function
and then in the worksheet cell E1 enter:
=KonKaType(A1:D1)

Excel VBA cross-sheet referencing

This is my first attempt at using VB in excel so bear with me.
I have a column of names where there are multiple duplicates of each, then in another column is the hours that each person as spent on a particular project. What my function does is goes down the list of names and each time it finds a match with $name it adds the corresponding hours up then returns the total.
Now this works when the table I'm getting the input from is on the same sheet as I'm using the Function, however I want to have the results on a separate sheet from the table. I believe its an issue with how its referencing the cell in line 10 but I'm not sure how to resolve this.
Function Hours(start as Range, finish As Range, name As String) As Double
Hours = 0#
RowStart = start.Row
RowFinish = finish.Row
NameColumn = start.Column
HourColumn = finish.Column
For i = RowStart To RowFinish
If Cells(i, NameColumn) = name Then Hours = Hours + Cells(i, HourColumn).Value
Next i
End Function
As David pointed out, pass in the range from the other sheet and manipulate the data from there. See following UDF.
Function GetTotalHours(EmpNameR As Range, EmpName As String) As Double
Dim CellR As Range, HoursTotal As Double
HoursTotal = 0
For Each CellR In EmpNameR
If CellR.Value = EmpName Then
HoursTotal = HoursTotal + CellR.Offset(0, 1).Value
End If
Next
GetTotalHours = HoursTotal
End Function
In action:
Sheet1:
Sheet2:
Hope this helps.
you can access any sheet by index of by name, I always prefer by name.
Sheets("my_output_sheet_name").cells(row#, col#).value = total_hours
WHen you do "Cells(i, NameColumn)" it is assuming the current/active sheet. Doing what i said above, allows you to access any sheet regardless of which one is active.
So assuming you want to also list the names in the results sheet, right after the for loop, you could do:
Sheets("results").Cells(resultRow, NameColumn).value = name
Sheets("results").Cells(resultRow, HourColumn).value = Hours
where obviously you have a sheet called "results" and you will increment "resultsRow" after every name.
I realize this does not answer your VBA question, but there is a much easier way to do this within Excel without VBA. Try:
=SUMPRODUCT((NameColumn="Name")*Hours)
The forumula works by testing each name in NameColumn (a named range- you can replace it with the address of your data) with "Name" which results in an array of TRUE and FALSE values. When that array is multiplied by Hours range (also a named range), TRUE values are converted to 1s, and FALSE values are 0s. Then SUMPRODUCT() adds the result.

How to do SUMIFS text match with multiple criteria from another column?

I wish to categorize my transactions in a way where I can alter the categories on the fly. I think it's easier explained by showing what I have.
I have the following tables
Transactions
A: Date
C: Name
D: Amount
Fast Food List:
L: Name (partial name since going to be doing string search)
I wish to sum the transaction amount based on multiple criteria, such as date and category. Here's a formula that works:
=SUMIFS(D:D,A:A,"*03/2013*",C:C,"*"&L3&"*")
There's one fundamental problem: it only supports ONE item from the Fast Food List. Is there any way I can simply do a text stringth search across the entire Fast Food names?
""&L3&"" to ""&L:L&"" or something?
Here are some things I've tried.
1) Modify the SUMIFS criteria ""&L3&"" with a boolean UDF. The issue I run into here is that I can't figure out how to pass the current Row being looped by SUMIF into the function.
Public Function checkRange(Check As String, R As Range) As Boolean
For Each MyCell In R
If InStr(Check, MyCell.Value) > 0 Then
checkRange = True
End If
Next MyCell
End Function
If I could send Check to this function, well I would be set.
2) Replace the sum_range of the SUMIFS with a UDF that returns the range of rows
Public Function pruneRange(Prune_range As Range, Criteria_range As Range) As Range
Dim Out_R As Range
Dim Str As String
ActiveWorkbook.Sheets("Vancity Trans").Activate
' Loop through the prune_range to make sure it belongs
For Each Cell In Prune_range
' loop through criteria to see if it matches current Cell
For Each MyCell In Criteria_range
If InStr(Cell.Value, MyCell.Value) > 0 Then
' Now append cell to Out_r and exit this foreach
' Str = Str & Cell.Address() & ","
Str = Str & "D" & Cell.Row() & ","
Exit For
End If
Next MyCell
Next Cell
' remove last comma form str
Str = Left(Str, Len(Str) - 1)
' use str to set the range
Set Out_R = Range(Str)
' MsgBox (Str)
Set pruneRange = Out_R
End Function
This works for a regular SUM loop, but for some reason it returns #Value when I try using it in a SUMIF or SUMIFS. Another issue is that even in the SUM loop if use C:C instead of C1:CX where X is however many rows, it crashes excel or takes forever to loop through. I'm guessing it's because excel doesn't know when to stop in a UDF unless I somehow tell it to?
Try this formula
=SUMPRODUCT(SUMIFS(D:D,A:A,"*03/2013*",C:C,"*"&L3:L30&"*"))
By using a range (L3:L30) for the final criterion the SUMIFS formula will generate an "array" (of 28 values - one for each value in L3:L30) ...and SUMPRODUCT is used to sum that array and get the result you want

Excel Lookup return multiple values horizontally while removing duplicates

I would like to do a vertical lookup for a list of lookup values and then have multiple values returned into columns for each lookup value. I actually managed to do this after a long Google search, this is the code:
=INDEX(Data!$H$3:$H$70000, SMALL(IF($B3=Data!$J$3:$J$70000, ROW(Data!$J$3:$J$70000)-MIN(ROW(Data!$J$3:$J$70000))+1, ""), COLUMN(A$2)))
Now, my problem is, as you can see in the formula, my lookup range contains 70,000 rows, which means a lot of return values. But most of these return values are double. This means I have to drag above formula over many columns until all lookup values (roughly 200) return #NUM!.
Is there any possible way, I guess VBA is necessary, to return the values after duplicates have been removed? I'm new at VBA and I am not sure how to go about this. Also it takes forever to calculate having so many cells.
[Edited]
You can do what you want with a revised formula, not sure how efficient it will be with 70,000 rows, though.
Use this formula for the first match
=IFERROR(INDEX(Data!$H3:$H70000,MATCH($B3,Data!$J3:$J70000,0)),"")
Now assuming that formula in in F5 use this formula in G5 confirmed with CTRL+SHIFT+ENTER and copied across
=IFERROR(INDEX(Data!$H3:$H70000,MATCH(1,($B3=Data!$J3:$J70000)*ISNA(MATCH(Data!$H3:$H70000,$F5:F5,0)),0)),"")
changed the bolded part depending on location of formula 1
This will give you a list without repeats.....and when you run out of values you get blanks rather than an error
Not sure if you're still after a VBA answer but this should do the job - takes about 25 seconds to run on my machine - it could probably be accelerated by the guys on this forum:
Sub ReturnValues()
Dim rnSearch As Range, rnLookup As Range, rnTemp As Range Dim varArray
As Variant Dim lnIndex As Long Dim strTemp As String
Set rnSearch = Sheet1.Range("A1:A200") 'Set this to your 200 row value range
Set rnLookup = Sheet2.Range("A1:B70000") 'Set this to your lookup range (assume 2
columns)
varArray = rnLookup
For Each rnTemp In rnSearch
For lnIndex = LBound(varArray, 1) To UBound(varArray, 1)
strTemp = rnTemp.Value
If varArray(lnIndex, 1) = strTemp Then
If WorksheetFunction.CountIf(rnTemp.EntireRow, varArray(lnIndex, 2)) = 0 Then 'Check if value exists already
Sheet1.Cells(rnTemp.Row, rnTemp.EntireRow.Columns.Count).End(xlToLeft).Offset(0, 1).Value =
varArray(lnIndex, 2)
End If
End If
Next Next
End Sub

Resources