Checking if each number in a list is between multiple ranges - excel

I have a list of numbers (that will be changed weekly) and I also have a list of ranges (that also change weekly). I need to check whether each number falls between each range.
Eg. My list of numbers on the left and my list of ranges on the right.
4 1 3
10 67 99
54 120 122
155
So what I need is to return a value if 4 falls between 1-3, then check if it falls between 67-99 and so on. Then return a value if 10 falls between 1-3 or 67-99 etc.
I have tried array and vba but I'm noob and I cant find much in the way of examples for this issue. I have had success with the following nested if;
=IF(OR(AND(G2>$L$2,G2<$M$2),AND(G2>$L$3,G2<$M$3),AND(G2>$L$4,G2<$M$4),G2,"")
=IF(OR(AND(G3>$L$2,G3<$M$2),AND(G3>$L$3,G3<$M$3),AND(G3>$L$4,G3<$M$4),G3,"")
However, once my number of ranges gets above a certain number it says i have too many characters.
Any help would be appreciated.
Regards,
Will.

So what I need is to return a value if 4 falls between 1-3, then check if it falls between 67-99 and so on. Then return a value if 10 falls between 1-3 or 67-99 etc.
If you want to match each value in col G with the list in L and M then, rearrange the G column values in a row as shown below so that you can get the entire view in one go.
Put this formula =(AND($N$1>L2,$N$1<M2)) in N2 and drag it down. Similarly put the formula =(AND($O$1>L2,$O$1<M2)) in O2 and pull it down and so on...

Thanks Siddarth. This works but the number of rows will be changing weekly and your method would be too tedious to do weekly.
Ended up working it out on my own. Pretty simple but took me forever!
Sub Subtract_Start()
Set rng1 = Range(Range("G2"), Range("G2").End(xlDown))
Set rng2 = Range(Range("L2"), Range("L2").End(xlDown))
For i = 2 To rng1.Rows.count
For j = 2 To rng2.Rows.count
If Cells(i, "G").Value > Cells(j, "L").Value Then
If Cells(i, "G").Value < Cells(j, "M").Value Then
Cells(i, "G").Copy Cells(i, "J")
End If
End If
Next j
Next i
End Sub

Related

Dynamic Range division with two variables

I'm trying to complete division for a dynamic range with two variables and it keeps dividing the dynamic range by the last number in the range. Below is my VBA code.
For i = 2 To 8
For r = 13 To 19
If ThisWorkbook.Sheets("Sheet1").Cells(i, 28) = "" Then
ThisWorkbook.Sheets("Sheet1").Cells(r, 28) = ""
Else
ThisWorkbook.Sheets("Sheet1").Cells(r, 28) = ThisWorkbook.Sheets("Sheet1").Cells(i, 28) / Range("$AB$8")
End If
Next r
Next i
Essentially it is dividing the last i value (Cell row 8) by the Range("$AB$8") (cells row 19).
What I would like to happen is the values in rows i to divide by Range("$AB$8")....in other words the value in cell (2,28)/ab8, (3/28)/ab8, (4,28)/ab8 etc etc.
It current is taking the value in cell (8,28) dividing it by ab8...and applying it to all defined r rows.
There are a number of issues here - all of which are small tweaks but end up with the wrong result you are seeing.
Your example code is not a dynamic range. You have hardcoded Cells(AB2:AB8) and Cells(AB13:AB19). You just did it in a way that is not obvious.
Also not very obvious is that you are writing the results to a single column. See the pattern here:
Loop 1: i = 2, results may be writing to Cells(AB13:AB19)
[…]
Loop 7: i = 8, results may be writing to Cells(AB13:AB19)
I said "may" because you have the If statement.
Depending on what you really want to happen, the code can be amended.
Instead off the first loop put a conditional there (e.g. If all cells
in that range are blank then …, or if any cells are blank then ...)
Use an Exit For after fixing the first blank loop
Also address the column (i.e. results spread across multiple columns)
Use a single loop (For i = 2 to 8 … and then adjust r according to i… r = i+12)

extract number between characters and order them

Hey I am thinking about a solution for my problem for hours now. I've searched the web, too and was able to find some approaches but none of them does work for my problem.
I have one cell with data that appears like this:
(Monday#100%[00:00-24:00]);(Tuesday#100%[00:00-24:00]);(Wednesday#100%[00:00-24:00]);(Thursday#100%[00:00-24:00]);(Friday#100%[00:00-24:00]);(Saturday#100%[00:00-24:00]);(Sunday#100%[00:00-24:00])
The problem is, that this string is not consistent. It could also look like this:
(Monday#125%[00:00-04:00]);(Monday#90%[04:00-08:00]);(Monday#90%[08:00-12:00]);(Monday#115%[12:00-16:00]);(Monday#120%[16:00-20:00]);(Monday#115%[20:00-24:00]);(Tuesday#125%[00:00-04:00]);(Tuesday#90%[04:00-08:00]);(Tuesday#90%[08:00-12:00]);(Tuesday#115%[12:00-16:00]);(Tuesday#120%[16:00-20:00]);(Tuesday#115%[20:00-24:00]);(Wednesday#125%[00:00-04:00]);(Wednesday#90%[04:00-08:00]);(Wednesday#90%[08:00-12:00]);(Wednesday#115%[12:00-16:00]);(Wednesday#120%[16:00-20:00]);(Wednesday#115%[20:00-24:00]);(Thursday#125%[00:00-04:00]);(Thursday#90%[04:00-08:00]);(Thursday#90%[08:00-12:00]);(Thursday#115%[12:00-16:00]);(Thursday#120%[16:00-20:00]);(Thursday#115%[20:00-24:00]);(Friday#125%[00:00-04:00]);(Friday#90%[04:00-08:00]);(Friday#90%[08:00-12:00]);(Friday#115%[12:00-16:00]);(Friday#120%[16:00-20:00]);(Friday#115%[20:00-24:00]);(Saturday#125%[00:00-04:00]);(Saturday#90%[04:00-08:00]);(Saturday#90%[08:00-12:00]);(Saturday#115%[12:00-16:00]);(Saturday#120%[16:00-20:00]);(Saturday#115%[20:00-24:00]);(Sunday#125%[00:00-04:00]);(Sunday#90%[04:00-08:00]);(Sunday#90%[08:00-12:00]);(Sunday#115%[12:00-16:00]);(Sunday#120%[16:00-20:00]);(Sunday#115%[20:00-24:00])
The structure of the string is
You have a day of the week followed by an "#"
after the at (#) you have a number that can be between 0 and 999
after that you have a time of the day in brackets []
You can have up to 6 different time frames of one day (not more, but less)
each time frame cluster is separated by ; and within normal brackets ()
So this is my starting position. What I want is to extract the numbers between # and % and list them chronologically (Monday to Sunday, hours of the day).
I was able to extract the number between # and % for each day of the week with this formula
=MID(B3;SEARCH("Monday#";B3)+7;SEARCH("%";B3)-SEARCH("Monday#";B3)-7)
But this only works if each day of the week is mentioned only ones.
I am out of ideas of how I could get it to work when having more time frames per day. Appreciate any help.
Thanks,
Ramon
Try an set of iterative searches, where the next search starts at the position found for the previous result. ie:
in cell B6 put =SEARCH("]",$B$3,B5+1)
in cell C6 put =MID($B$3,SEARCH("(",$B$3,B5+1)+1,SEARCH("#",$B$3,B5+1)-SEARCH("(",$B$3,B5+1)-1)
in cell D6 put =MID($B$3,SEARCH("[",$B$3,B5+1)+1,SEARCH("]",$B$3,B5+1)-SEARCH("[",$B$3,B5+1)-1)
in cell E6 put =MID($B$3,SEARCH("#",$B$3,B5+1)+1,SEARCH("%",$B$3,B5+1)-SEARCH("#",$B$3,B5+1)-1)
(Note that B5 needs to be empty (or 0) for this to start correctly)
You can then fill down as far as needed to pick up each term. If they are out of order, then you can order on column D then C (the time then the day).
This might get you started.
Sub Extractor()
Dim data() As String, i As Integer, rw As Integer
rw = 3
data = Split(Range("A1"), ";")
For i = 0 To UBound(data)
Range("A" & rw) = VBA.Mid$(data(i), 2, InStr(1, data(i), "#") - 2) 'Day
Range("B" & rw) = VBA.Mid$(data(i), InStr(1, data(i), "#") + 1, InStr(1, data(i), "%") - InStr(1, data(i), "#") - 1) '% number
Range("C" & rw) = VBA.Mid$(data(i), InStr(1, data(i), "[") + 1, InStr(1, data(i), "]") - InStr(1, data(i), "[") - 1) 'Time
rw = rw + 1
Next i
End Sub
Notes:
Assumes your string is in A1
Prints your data in columns A, B, and C starting in row 3
You can use Text-to-Columns feature of excel, with ) as a delimiter. Than transpose the columns into rows to get something like this:
(Monday#125%[00:00-04:00]
;(Monday#90%[04:00-08:00]
;(Monday#90%[08:00-12:00]
;(Monday#115%[12:00-16:00]
;(Monday#120%[16:00-20:00]
...
;(Sunday#115%[20:00-24:00]
Then apply formulas.
Edit:
Using just Find and Mid you can achieve this:
The idea behind find and mid is always the same.
Ex. for finding ( is =FIND("(";[Text]).
Ex. for extracting Day is =MID([Text];[#[Pos(]]+1;[#[Pos'#]]-[#[Pos(]]-1)

Need formula for excel, to subtract the number "9" to each number individually and

I want you to have some fun. I need something specific.
First i must explain what i do. I use a simple codification for product prices at retail store, because i dont want people know the real price for themselves. So i change the original numbers to another subtracting the number 9 for each number.
Normally I manually write down all the prices with this codification for every product.
So.. for example number 10 would be 89. (9-1 = 8) and (9-0 = 9)
Other examples:
$128 = 871
$75 = 24
$236 = 763
$9 = 0
Finally i put 2 number nines (9) at the beginning of the codified price also, to confuse people who might think that number could be the price.
So the examples i used before are like this:
99871 (means $128)
9924 (means $75)
99763 (means $236)
990 (means $9)
Remember that i need 2 (two) nines before the real price. The real prices never start with 0 so, the nines at the beginning exist only to confuse people.
Ok. So, now that you understand, here comes the 2nd part.
I have an excel whith hundreds of my products added, with prices, description, etc. And i decided it is time to use a printer and start to print this information from excel. I have a software to do that, but first i need to have the codified prices in the excel also.
The fun part begins when i want to convert the real prices that are already written in my excel document into a new column AUTOMATICALLY. So that way i don´t have to type again all the prices in codified form for the old and new items i add in the future.
Can someone help me with this? Is it even possible?
I tried with =A1-9999 but, it works well with 2 character number only. Because if the real price is 5, i will get 3 nines: 9994(code). And if the price is 234 i will get only 1 nine 9765(code). And it is a condition i need to have the TWO nines at first.
Thank you very much in advanced!
Though you have requested for formula , I am suggesting VBA program which seems to me very convenient.
You have to open VBE and insert a module and copy the program. Change the code lines wherever indicated to suit your requirements for sheets etc.
Sub NumberCode()
Dim c As Range
Dim LR As Integer
Dim numProbs As Long
Dim sht As Worksheet
Dim s As Integer
Dim v As Long
Dim v1 As Long
Set sht = Worksheets("Sheet1") ' change as per yr requirement
numProbs = 0
LR = sht.Cells(Rows.Count, "A").End(xlUp).Row
For Each c In sht.Range("A1:A" & LR).Cells
s = Len(c)
v = c.Value
v1 = 99
For s = 1 To Len(c)
v1 = v1 & (9 - Mid(c, s, 1))
Next
c.Offset(0, 1).Value = v1
v1 = 99
numProbs = numProbs + 1
Next
MsgBox "Number coding finished"
End Sub
Sample sheet of results is appended below.
I will be using helper cells but you could dump it all into one cell if you want since you are only dealing with 4 characters.
For the purpose of this example, I am assuming your original price list starts in B11.
=IFERROR(9-MID($B11,COLUMN(A1),1),"")
Place that in D11 and copy to the right three more times so you have it from D11 to G11. That formula strips off 1 character from your price and subtracts that character from 9. When you go the next column it repeats itself. If you do not have that many characters, it will return "".
In C11 you will build your number based on the adjacent 4 columns using this formula:
="99"&D11&E11&F11&G11
It places 99 in front then adds the numbers from the adjacent 4 columns.
Select cells C11 to G11 and copy and paste downward beside your data column as far as you need to go.
An alternate more concise method would be:
=REPT(9,LEN(B11)+2)-B11
Perhaps I'm missing something, though simply:
=REPT(9,2+LEN(A1))-A1
seems good to me.
Regards

Comparing Decimal Values Excel VBA

I am trying to compare decimal values in Excel VBA and delete rows that
match the criteria. This was my original code and it skipped over many rows.
For Each i In WSData.Range("A7", WSData.Range("A7").End(xlDown)).Cells
If i.Offset(0, 3).Value >= 98 Then
i.EntireRow.Delete
End If
Next
And the values on the spreadsheet are decimal values just with the % sign.
I tried "> 97.99" because Excel has some issues with floating point comparison but it still doesn't accurately compare.
Here is what it shows after using Selection.Value.
Percentages are decimal depicted with integers. For example 100.00% is stored as 1 and 98.01% is stored as .9801.
Therefor you need to adjust the threshold:
For Each i In WSData.Range("A7", WSData.Range("A7").End(xlDown)).Cells
If i.Offset(0, 3).Value >= .98 Then
i.EntireRow.Delete
End If
Next
The second problem is that when deleting rows it is best to iterate backwards. Otherwise it might miss some rows, because as each row is deleted it is moved up and then the next iteration skips the next row.
Change i from a range to a long and use this:
For i = WSData.Range("A7").End(xlDown).row to 7 Step -1
If WSData.Cells(i,3).Value >= .98 Then
Row(i).Delete
End If
Next
Edit: Because it appears there is a custom mask on the number format that is forcing numbers to look like percentages try this:
For i = WSData.Range("A7").End(xlDown).row to 7 Step -1
If WSData.Cells(i,3).Value >= 98 Then
Row(i).Delete
End If
Next
If this works then your main problem was that you were looking at column D. The offset is additive. So when you used .offset(0,3) it was moving three columns from column A. 1 + 3 is 4.

Excel: create sortable compound ID

All, I asked a question "Excel VBA: Sort, then Copy and Paste" and received two excellent answers. However, because I failed to provide sufficient user requirements, they won't work: I asked for a fix to the existing solution I created, instead of specifying the actual business need and seeing if anyone has a better way.
(sigh) Here goes:
My boss asked me to create a ss to log issues. He wants a compound ID that concatenates the "Assigned Date" with a number that indicates what number issue it is for that day only. A new day, the count must restart at 1. E.g.:
Assigned Issue Concatenated
Date & Count = ID
5/11/2011 & 1 = 5112011-1
5/11/2011 & 2 = 5112011-2
5/11/2011 & 3 = 5112011-3
5/12/2011 & 1 = 5122011-1
I solved this with a hidden column C that calculates =IF(D2<>D1,1,C1+1), thus calculating the Issue Count by incrementing the previous issue count if the assigned date in column D is the same as the previous date, and starting over at 1 when the date changes. Another column concatenates the assigned date and the issue count, and I have my issue ID.
Quick, easy, elegant, in, out, and done. Right? But when I delivered the ss, he pointed out that if you (that is, he) sorts any part of the spreadsheet, the issue ID goes out of sequence. Of course---each formula isn't referencing the previous date in sequence if the rows are sorted out of Assigned Date order.
My immediate thought, which prompted my previous question, was to first re-sort the Assigned Date order correctly, then copy and paste the value of the calculated Issue Count to lock it in, and thus preserve the concatenated ID.
The only other way I can see to do this (in VBA, natch) is to:
evaluate all the dates in the Assigned Date column
evaluate all the numbers in the Issue Count column
calculate the latest sequential Issue Count for an a new item assigned on a given Assigned Date
Assign that sequential Issue Count to the new item
It'd be nice to then place the cursor into the next cell that the user would ordinarily go to, which would be the one right adjacent to the just-entered Assigned Date; however, that isn't necessary
That would avoid the need to re-sort the physical ss. However, besides a hazy guess that this would involve VLOOKUP, I got nothing. I couldn't find anything through searching.
Can anyone help? Or suggest a place to go? Thanks!!!
Sounds like you just want to automate a Paste Special action. The following replaces the formulas in a1:a100 with their calculated values:
Set src = ActiveSheet.Range("a1:a100")
src.Copy
src.Select
Selection.PasteSpecial Paste:=xlPasteValues, _
Operation:=xlNone, _
SkipBlanks:=False, _
Transpose:=False
I think the formula =IF(D2<>D1,1,C1+1) could be improved as this relies on dates being in order. The following will preserve the count for any order that is sorted
Assume
ColA ColB ColC
Row1 Assigned_Date Issue Count Concatenate
Row2 05/11/2011 =COUNTIF($A$1:A2,A2) =TEXT(A2,"ddmmyyyy")&"-"&B2
Row3 05/11/2011 =COUNTIF($A$1:A3,A3) =TEXT(A3,"ddmmyyyy")&"-"&B3
Row4 05/12/2011 =COUNTIF($A$1:A4,A4) =TEXT(A4,"ddmmyyyy")&"-"&B4
Row5 05/11/2011 =COUNTIF($A$1:A5,A5) =TEXT(A5,"ddmmyyyy")&"-"&B5
Essentially enter B2 and C2 formulae and drag down. You might need to swap ddmmyyyy to mmddyyyy as we use dates first rather than months :)
Also, note the locking of the first part of the range only using $ - $A$1:Ax
This works perfectly for your current question but does not work if the Issue Count is assigned in time order per date.
How about using a procedure? Just click a button to add the next entry.
I've assumed that the entries will be given today's date and that the sheet layout is:
Rows: 1 = Title / 2 = left blank / 3 = Headings of the data block
Columns: A = Date / B = Issue Count / C = Combined ID / D etc = other data
Sub AddEntry()
Dim iDayRef As Long, iNumRows As Long, n As Long
With Range("A3")
iNumRows = .CurrentRegion.Rows.Count
For n = 2 To iNumRows
If .Cells(n, 1).Value = Date Then
If .Cells(n, 2).Value > iDayRef Then iDayRef = .Cells(n, 2).Value
End If
Next
.Cells(iNumRows + 1, 1).Value = Date
.Cells(iNumRows + 1, 2).Value = iDayRef + 1
.Cells(iNumRows + 1, 3).Value = Format(Date, "mm/dd/yyyy") & " - " & iDayRef + 1
.Cells(iNumRows + 1, 4).Select
End With
End Sub
And do you really need three columns for Date, Count, and Combined ID? If you went with a
yyyy/mm/dd - xx
ID format, one column could replace all three, and you could easily sort on it.

Resources