In Sheet1 I have several input values x, y and z in columns A, B and C. To simplify let's say I only have two rows with values (as in the picture).
In Sheet2 I have the thresholds; min and max-values for x, y and z, in addition to the corresponding codes.
I want to retrieve, in Sheet1, all codes where the input values fall within the thresholds (matching the values) in Sheet2. The codes do not need to be listed in the same cell if this complicates things; they can be listed in separate columns. I am also open for both formulas and VBA.
I know how to list several results using JOINTEXT if the criteria are exact matches. I also know how to list one result based on several inaccurate matches using INDEX + MATCH + <= >=. I don't know how to combine them.
I looked at these:
EXCEL index match by multiple criteria AND multiple match types?
https://exceljet.net/formula/multiple-matches-in-comma-separated-list
https://exceljet.net/formula/index-and-match-with-multiple-criteria
...and tried this:
=INDEX(F5:L8;SMALL(IF(COUNTIF(F5:F8;"<="&A5)*COUNTIF(G5:G8;">"&A5)*COUNTIF(H5:H8;"<="&B5)*COUNTIF(I5:I8;">"&B5)*COUNTIF(J5:J8;"<="&C5)*COUNTIF(K5:K8;">"&C5);ROW(F5:L8)-MIN(ROW(F5:L8))+1);COLUMN(F4));ROW(F4)+6)
...without any result.
I managed to solve it by using Jeeped's impressive code (see comments). However, since I'm using comma (,) as decimals-seperator I needed to include a small adjustmen. I changed "iOptions", "iIgnoreHeaderRows", "i" and "j" from Variant to Double, and "a" from Variant to Long. I also included the following code:
Dim counter As Integer, sizeOfPairs As Integer
Dim test As String
counter = 0
sizeOfPairs = UBound(pairs, 1)
For counter = 0 To sizeOfPairs
If TypeName(pairs(counter)) = "String" Then
pairs(counter) = Replace(pairs(counter), ",", ".")
End If
Next counter
Related
I am relatively new to Excel VBA that's why I have some problems.
I have constructed a (Poisson-) matrix with range "EB5:EV25" where each cell contains a formula that basically (not only) multiplies two input values, e.g. they look like
=POISSON(0;$H$2;FALSE)*POISSON(0;$H$2;FALSE)
where "$H$2" and "$H$2" are my first two input values.
The results are presented in "EB33:ED33" where in each of the three cells the sum of a certain part of the matrix above is summed up.
Lets say the column with one of the input values is H and the column with the other input values is K (the values are in every 82th row). Thus for every 82th row of column H and K my matrix in "EB5:EV25" calculates results and presents them in "EB33:ED33". This solution so far only allows for presenting the results of one pair of input variables at a time - I need to change the row of input variables in my matrix manually.
However I don't finally want to present my results in "EB33:ED33" but in a different column, say "BA:BC", 2 rows after the row that contains the input values (separately for each row of input values).
I have already tried out some code but I am not even able to work with input variables that are in different columns, neither does my code change the input values - for each row of input values the results are always the same (i does not change).
Dim i As Integer
Dim rng As Range
Set rng = Range("EB5:EV25")
For i = 3 To Cells(Rows.Count, 8).End(xlUp).Row Step 82
rng.Replace "$" & i - 1, "$" & i
Application.Calculate
Range("EB33:ED33").Copy
Cells(i + 1, 63).PasteSpecial xlValues
Next i
Set rng = Nothing
End Sub
Would be great if anybody is able to help!
Is it possible to extract the resulting value of a nested sub-function in VBA?
For example, from this INDEX-MATCH look-up function, I would like to find the value from the results from the two MATCH() functions:
=+INDEX(Sheet3!$B$5:$I$15;MATCH($A6;Sheet3!$A$5:$A$15;0);1)
I am looking for a macro that can return the value of the nested MATCH() function as an input in a VBA code. That is, I realize I could extract the MATCH() subfunction and have VBA paste it as a value. What I want is identify the value of the MATCH() function and calculate with it within my VBA script.
As I'm not quite following what you're saying, I'll take a guess... you want to use the match() scenario separately?
dim x as long, y as long, z as string
x = application.match($A" & ActiveCell & ",Sheet3!$A$5:$A$15,0)"
y = x*3 'perform some work using the row number x, knowing match of 1 = row 5 on sheet3
z = application.index(Sheet3!$B$5:$I$15," & y & ")"
Took that a step further where you can utilize said arithmetic'd match value.
Inherently, the match only provides a row number from your array, so i don't know what the "extract" you are referring to would be. If you are looking to extract a value that you're matching to, then you'll just end up with what is (from your example) in A6.
Edit: Updating code to be usable (previously just gave a concept)
dim x as long, y as long, z as string
with sheets("Sheets3")
x = application.match(ActiveCell.value,.range(.cells(5,"A"),.cells(15,"A")),0)
y = x*1 'perform some work using the row number x, knowing match of 1 = row 5 on sheet3
z = application.index(.range(.cells(5,"B"),.cells(15,"B")),y) 'This index was changed to be a SINGLE COLUMN (was B5:I15)
end with
I am new to programming altogether, however my work assignments sometimes force me to automate some processes in Excel. Anyway, I wanted to calculate an average of n consecutive minimum values within a column for a given condition. I managed to find a code from user "Gary's Student" from July 2015, which fits just about perfect to my needs except I had to change Sums to Averages, however, since my programming skills are close to 0, I tried but hadn't succeeded to calculate those values for a given condition. For example (See picture in the following link.Excel columns example)in the column 2, the average of 3 consecutive minimum values is 44, however I'd like to add a condition for example, to calculate the average of 3 consecutive minimum values if the value/text in the first column is "B". The answer should obviously be 250.
Below is the initial VBA code:
Public Function consec(rng As Range, x As Long) As Double
Dim r As Range, i As Long, mymin As Double, temp As Double
Dim wf As WorksheetFunction
Set wf = Application.WorksheetFunction
i = 1
Set r = rng(i).Resize(x, 1)
mymin = wf.Average(r)
For i = 2 To rng.Count - x + 1
Set r = rng(i).Resize(x, 1)
temp = wf.Average(r)
If temp < mymin Then
mymin = temp
End If
Next i
consec = mymin
End Function
Any help is much appreciated.
Thanks.
To bypass vba the following array formula will achieve what you want:
=AVERAGE(SMALL(IF($A$2:$A$12=$E$1,$B$2:$B$12),ROW(INDIRECT("1:" & E2))))
Being an array formula it must be confirmed with Ctrl-Shift-Enter when exiting edit mode. If done properly excel will put {} around the formula.
The ROW(INDIRECT("1:" & E2)) part is what determines how many of the lowest amounts to average. It iterates from 1 or the lowest to what ever value is in E2, in this case 3 or the third.
The IF() statement; IF($A$2:$A$12=$E$1,$B$2:$B$12) puts together an array of values that meet the criteria, In this case column A being equal to what is in E1 or 'B'.
The SMALL() function uses the array from the IF() and the Iteration from the first to get the smallest in the array and returns those values to the AVERAGE() Function.
I have been using Excel (2010) at lot more for work and I've been trying to excel get better at using this tool.
What I want to do in the end is compare the value of a cell to multiple ranges of values (each range is its own category). If the initial value matches a value in one of the ranges/category, then the end result would be to display what category it came from. Some categories are ranked higher than others, so the higher ranked category takes precedent over lower ranked ones
Since this seems a little complicated for me to tackle (I am a novice), I decided to start from a simpler, example problem and work my way up:
I have 10 cells with values 1 - 10. I have two categories, one for odd numbers, and one for even numbers. I got my formula to work with:
=IF(COUNTIF($A$14:$A$18,A2),CELL("contents",$F$2),IF(COUNTIF($A$21:$A$25,A2),CELL("contents",$F$3),"ERROR"))
where A2 = cell which I am comparing to the other ranges
$A$14:$A$18 = my range of odd numbers
$F$2 = "ODD"
$A$21:$A$25 = my range of even numbers
$F$3 = "EVEN"
Now, I wanted to add a 3rd category that has a higher rank than the two I have, a "PRIME" number category. Seeing how 2 is both from the "EVEN" category and the "PRIME" category, I would like the "PRIME" number category to be displayed and override any other category.
Is something like this possible?
Just by phone (may contain errors) for VBA:
Public Function getRangeName(str As String) As String
Dim MyRanges as Variant, MyNames As Variant, i As Long
MyRanges = Array(Range("A1:A10"), Range("B1:B10"), Range("C1:C10"))
MyNames = Array("Range A", "Range B", "Range C")
For i = 0 To 2
If IsNumeric (Application.Match(str, MyRanges(i), 0)) Then
getRangeName = MyNames(i)
Exit Function
End If
Next
End Function
It will stop at the first range it finds and output it and nothing "" if it was nowhere
Also if the ranges stick together you could use something like that:
=IFERROR(CHOOSE(MAX((A1:C8="Search String")*COLUMN((A1:C1))),"range a","range b","range c"),"")
As an array formula (formula needs to be confirmed with CTRL+SHIFT+ENTER) it will output the highest range (c > b > a)
Doing it for non-contiguous ranges which are at least at the same height (going for A1:A10, C1:C10 and E1:E10 only)
=IFERROR(CHOOSE(MAX((A1:E10="Search String")*{2,0,3,0,1}),"range e","range a","range c"),"")
also the order is different (c > a > e)... also needs to be confirmed with CTRL+SHIFT+ENTER
I tried to use the MATCH function in an array formula to return multiple matches (by default it only returns the first match). However, this doesn't seem to work. How can I solve this problem without a complex, unreadable formula?
How about this, without VBA? [entered on cell C9 as an array formula with CTRL + SHIFT + ENTER, where your searched column is A9:A24, and your search terms are in B1:B4], and dragged down to find multiple hits?
=SMALL(IFERROR(MATCH($B$1:$B$4,$A$9:$A$24,0),""),ROW()-ROW($C$8))
This first uses the array formula to show each 'hit' for any of the search terms matched in the searched column, and then using the Small function with reference to the current cell's row, it returns the earliest hit, then the 2nd hit, then the 3rd hit, etc.
Beyond this point, the reference points to the searched array can be used as needed (converted to the row location of an index function, etc.).
EDIT
On further review of the results from this formula, it only returns a single hit for each search term, even if that search term appears multiple times. To resolve this, I first used the formula:
=SMALL(IF($A$9:$A$24=$B$1,ROW($A$9:$A$24),""),ROW()-ROW($E$8))
This shows each hit for a match of the search term found in B1. Here is where I am stuck. I could only figure out how to resolve with the admittedly manual:
=SMALL(IF($A$9:$A$24={"a","b","c"},ROW($A$9:$A$24),""),ROW()-ROW($E$8))
Any suggestions on how to improve to allow multiple hits for multiple terms?
EDIT - Additional option
Okay, I've determined another method of picking up multiple hits. This one relies on considering the location of the previous matches already made. Depending on what you want your result vector to look like (which was never specified by the OP), the results from this are clean but the formula is fairly messy.
The first cell looks like this, in cell H9:
=ADDRESS(MIN(IFERROR(MATCH($B$1:$B$4,$A$9:$A$24,0),""))+ROW($A$8),1)
This shows the address of the first cell which matches any of the search terms, using the formula noted further above.
The cell below that (and every cell after that), has this (also an array formula):
=ADDRESS(MIN(IFERROR(MATCH($B$1:$B$4,INDIRECT(ADDRESS(ROW(INDIRECT(H9))+1,1)):$A$25,0),""))+ROW(INDIRECT(H9)),1)
This picks up the address of the cell found in the row above (adding 1 row to avoid re-hitting the same term), and from that new search column from that point to the end point (adding 1 row so that it properly stops at the last ending hit), it re-searches for any of the terms.
This one is again, not that clean [Yes I know there are some improvements I could make to determining what the search should be - either using the text manipulation functions or even doing a relative name reference that changes as you move down the column], but it is automated and, I would argue, cleaner than a VBA module. Especially as, depending on what you want your result vector to be, this could be much simpler.
Working\developing on the formulas posted by #Grade'Eh'Bacon ended up with this formula to retrieve all the results of a match function with several matches for several items.
Assuming input range is B2:B17 and the range with the items to match is F3:F5 enter this FormulaArray in H3
=IFERROR( SMALL( IF( $B$3:$B$17 = TRANSPOSE( $F$3:$F$5 ),
1 + ROW( $B$3:$B$17 ) - ROW( $B$3 ), "" ), ROWS($2:2 ) ), "" )
It's an FormulaArray returning all matches for several items
All merits go to #Grade'Eh'Bacon for his great work on the subject.
It is not possible with the built-in MATCH, however, using a VBA macro, you can achieve this:
Public Function MATCH_RANGE(values As Variant, ary As Variant, match_type As Integer)
Dim i As Integer
Dim elementCount As Integer
Dim result()
Dim value As Variant
Dim arySize As Integer
arySize = UBound(ary.Value2, 1)
Dim valueSize As Integer
valueSize = UBound(values.Value2, 1)
ReDim result(0 To arySize, 0 To 1)
elementCount = 0
For i = 1 To arySize
For j = 1 To valueSize
value = values(j, 1)
If (match_type = -1 And ary(i, 1) <= value) Or (match_type = 0 And ary(i, 1) = value) Or (match_type = 1 And ary(i, 1) >= value) Then
result(elementCount, 0) = i
elementCount = elementCount + 1
End If
Next j
Next i
For i = elementCount To arySize
result(i, 0) = -100000000
Next i
MATCH_RANGE = result
End Function
This function both returns multiple matches and allows you to pass a range of multiple values that you want matched. I've found this useful a number of times. Feedback welcome to help improve this.
NOTE: You must spread this formula across a few cells using an array-formula (CRTL-SHIFT-ENTER), in order to see the multiple matches.