I am trying to think of a way to loop through a number of combinations making sure that I go through each available combination without repeat. Let me explain. I have a set of numbers, for example
20,000
25,000
27,000
29,000
and I would like to alter this set of numbers via a loop and copy the new numbers into a different sheet so that my formulas on that sheet can calculate whatever I need them to calculate. For example, the first couple of iterations might look something like this:
1st
20,000 x 1.001
25,000 x 1
27,000 x 1
29,000 x 1
2nd
20,002 x 1.001
25,000 x 1.001
27,000 x 1
29,000 x 1
The first row of numbers should never exceed the second. So 20,000 should only go as high as 25,000.
I was able to set up a system whereby I set up a matrix and then loop through a random set of combinations using =rand() however this does not ensure I hit every combination and also repeats combinations.
Can anyone explain the math behind this and also how I would use a loop to accomplish my goal?
Thank you!
Try starting with smaller numbers.
See if this works for you.
Sub looper()
'First Array
Dim myArray(9) As Double
For i = 1 To 10
myArray(i - 1) = i
Next i
'Second Array
Dim myOtherArray(9) As Double
For i = 1 To 10
myOtherArray(i - 1) = i
Next i
'Loop through each one
For Each slot In myArray
For Each otherSlot In myOtherArray
Debug.Print (slot & " * " & otherSlot & " = " & slot * otherSlot)
Next otherSlot
Next slot
End Sub
GD user1813558,
Your question contains too little detail and is too broadly scoped to be able to provide a accurate answer.
Are your numbers arbitrary (i.e. the ones you provided are 'just'
samples) or will they be fixed as per your indicated numbers ?
Will there always be only 4 numbers ?
Is the distribution of your startnumbers (i.e. their difference
value) always as per your indication 0, +5000, +2000, +2000
Will the results of all 'loops' (or iterations) need to be copied to
a different sheet ? (i.e looping from 20.000 to 25.000 by increments
of 1.001 would require about 223 iterations, and subsequently sheets,
before the result starts exceeding 25.000 ?)
Does a new sheet need to be created for each iteration result or are they
existent or will the result be copied to the same sheet for every iteration ?
In short, please provide a more accurate question.
Related
I have a worksheet that calculates various values based on a random value and would like to use the law of large numbers to converge to an average for each calculation.
I am thinking of using VBA to execute the calculation 1000's of times and store the values in a list for averaging at the end. My current testing code only stores the original value after each iteration. ie Safety1 does not change even though the value in R36 changes.
Dim Safety1(0 To 10) As Long
For i = 0 To 10
Safety1(i) = Sheet34.Range("R36").Value
Debug.Print Safety1(i)
Next i
myAverage = Application.WorksheetFunction.Average(Safety1)
myAverage should be the converging average.
R36 contains the sum of other ranges, which contain values based on rand()
If there is a better way to do this, i am happy to listen.
Thanks in advance.
This post resolved the problem. I needed to wait until the calculation process had completed before storing the value
Please do sheet calculate like this:
Dim Safety1(0 To 10) As Long
Application.ScreenUpdating = False
For i = 0 To 10
Worksheets("Sheet34").Calculate
Safety1(i) = Sheet34.Range("R36").Value
Debug.Print Safety1(i)
Next i
Application.ScreenUpdating = True
myAverage = Application.WorksheetFunction.Average(Safety1)
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
I'm new here, and I thought I would ask a question that certainly isn't found in the Microsoft Help Center and that I haven't been able to find a solution to either.
I am trying to calculate probability on things, and for the most part, Excel is very helpful in it. I'm running into problems though as I add additional variables.
My sheet currently is comparing dice rolls of 4 8-sided dice. 2 dice have certain symbols and the two other dice have different symbols. Some symbols negate each other, and in the end I come to a damage output number. When comparing 2 or 3 dice, the possible combinations are limited. 3 dice having 512 possibilities. With 4 now, there are 4096 possibilities and it's only going to get higher. This is why I need what I'm asking for.
Is there a way for a cell to understand is current position in reference to the block of cells it's currently in?
For example: I'm calculating a reroll possibility, but it will only happen half the time, meaning there are 12 possibilities of a single die with reroll option. So the current possibility table I'm developing is going to be 96 separate tables of 96 possible outcomes each. Table 1/1 is going to compare the first row of the 2 dice Attack roll table vs. the first row of the 2 dice Defense roll table. Row 1 Column 1 of this table is going to give the outcome of R1C1 of Attack table vs. R1C1 of Defense table. R1C2 of the table is going to give the outcome of R1C1 of Attack table vs. R1C2 of Defense table. R2C1 of this table will give the outcome of R1C2 of Attack table vs. R1C1 of Defense table, etc...
I know how to do the referencing to the tables, so I've made it so once I build one table, I can copy and paste it to build the other 96. But as I compare more dice rolls, this will quickly become too cumbersome to handle. If there is a way for a cell to understand where it's relative position is in a given block of cells (i.e. R2C1 of my example table understands that it is R2C1), it would cut down on my load immensely, and allow for me to continue building these probability tables so o can better understand tradeoffs in certain areas.
Any help is greatly appreciated.
Here's an Excel UDF I wrote for basic dice calculation %. It may not work directly for your example with negative/conditional outcomes, but it does have flexibility for testing more than one dice and the number of sides dice, so it might inspire you with some ideas. As previous comments suggested, if you gave exact parameters, you could probably get a specific example. My example returns a %. It currently only measures the probability of a single outcome, but you could do more than one formula per cell =DiceRollOdds(3,2)+DiceRollOdds(4,2) (to measure the probability of 3 and 4), or you can modify the code get something more specific.
Function DiceRollOdds(OutcomeToCheck As Integer, NumberOfDice As Integer, Optional SidesOnDice As Integer) As Double
Dim SuccessResult As Integer, FailedResult As Integer, SingleDice As Integer, RollResult As Integer
If SidesOnDice = 0 Then
SidesOnDice = 6
End If
Dim Rolls As Integer
For Rolls = 1 To (SidesOnDice ^ NumberOfDice)
RollResult = 0
For SingleDice = 0 To NumberOfDice - 1
RollResult = Int(Rolls / SidesOnDice ^ SingleDice) Mod SidesOnDice + 1 + RollResult
Next SingleDice
If RollResult = OutcomeToCheck Then
SuccessResult = SuccessResult + 1
Else
FailedResult = FailedResult + 1
End If
Next Rolls
DiceRollOdds = SuccessResult / (FailedResult + SuccessResult)
End Function
I'm having a bit of a brain freeze, I thought this would be simple but it's not coming to me. I need an equation to calculate the number of groups of 10 in a variable range of variable data. Here's a small example, the real thing has hundreds of numbers with a variable min and max:
Number Rounded number to nearest 10
303.9 300
285 290 - min
443 440
446.8 450
461.1 460 - max
428.83 430
428.545 430
445.835 450
427.215 430
429.97 430
Unique groups of 10
300
290
440
450
460
430
Answer = 6 groups
I don't want to use pivot tables or group functions, I'd rather keep it solely in VBA. Also I don't want to work out the rounded values first and then count the distinct ones because I'd like to use the number to dimension an array, which I'll then populate in a loop. Is there a clever bit of math that can give answer?
I'm not aware of any clever math to do this. You could do this with worksheet formulas:
=SUM(--(FREQUENCY(ROUND(r,dec_places),ROUND(r,dec_places))>0))
where r is the data range and dec_places is the amount of rounding (since you're rounding to the nearest 10s, dec_places = -1).
You could implement this in VBA with something like:
Function CountUniqueRounded(r As Range, dec_places As Double) As Long
' Implement this worksheet formula
' =SUM(--(FREQUENCY(ROUND(r,dec_places),ROUND(r,dec_places))>0))
Dim rAddr As String
Dim rFormula As String
Dim c As Long
' Build up the formula string
rAddr = r.Parent.Name & "!" & r.Address
rFormula = "ROUND(" & rAddr & "," & CStr(dec_places) & ")"
rFormula = "=SUM(--(FREQUENCY(" & rFormula & "," & rFormula & ")>0))"
' Debug.Print rFormula
c = Application.Evaluate(rFormula)
CountUniqueRounded = c
End Function
Hope this helps
I have an Array Formula solution which does not require VBA. Array Formulas take single function which would normally apply only to a single cell, and perform that function over a range of cells, returning an Array of different results (1 for each cell). That Array of results is then collapsed into a single number to give your answer.
Assuming your data is in column A, and goes for less than 1000 rows, this will work:
=SUM(IFERROR(MATCH(10*(ROW(A1:A1000)),ROUND(A1:A1000,-1),0)*0+1,0))
Note that to confirm an Array Formula, you need to press CTRL + SHIFT + ENTER, isntead of just ENTER.
What it does is multiplies 10 by each row from A1 to A1000, and then checks to see if that result can be found when rounding each cell present in A1 to A1000. That is, it checks 10, 20, etc. up to 1000, and tries to find it in a range of your rounded values. Whenever it finds a value, it multiplies the row it was found on by 0, and adds 1. Whenever it doesn't find a value (ie: returns an error), it shows 0. The sum of all matches gives you the number of times each rounded number from 10 - 1000 is found.
Caveat - this will not work if you have numbers > 1000; if such numbers would occur you can easily change all instances of 1,000 to 10,000. Likewise if your data sometimes extends further than row 1000, you will need to increase all instances of 1000 to an appropriate number. If data would vary wildly and you can't estimate size / max limit, then there are ways to automate this, but as the formula is already somewhat complex, I left that as a manual process.
I have a total data set that is for 4 different groupings. One of the values is the average time, the other is count. For the Total I have to multiply these and then divide by the total of the count. Currently I use:
=SUM(D32*D2,D94*D64,D156*D126,D218*D188)/SUM(D32,D94,D156,D218)
I would rather use a SumProduct if I can to make it more readable. I tried to do:
=SUMPRODUCT((D2,D64,D126,D188),(D32,D94,D156,D218))/SUM(D32,94,D156,D218)
But as you can tell by my posting here, that did not work. Is there a way to do SumProduct like I want?
I agree with the comment "It might be possible with masterful excel-fu, but even if it can be done, it's not likely to be more readable than your original solution"
A possible solution is to embed the CHOOSE() function within your SUMPRODUCT (this trick actually is pretty handy for vlookups, finding conditional maximums, etc.).
Example:
Let's say your data has eight observations and is in two columns (columns B and C) but you don't want to include some observations (exclude observations in rows 4 and 5). Then the SUMPRODUCT code looks like this...
=SUMPRODUCT(CHOOSE({1,2},A1:A3,A6:A8),CHOOSE({1,2},B1:B3,B6:B8))
I actually thought of this on the fly, so I don't know the limitations and as you can see it is not that pretty.
Hope this helps! :)
It might be possible with masterful excel-fu, but even if it can be done, it's not likely to be more readable than your original solution. The problem is that even after 20+ years, Excel still borks discontinuous ranges. Naming them won't work, array formulas won't work and as you see with SUMPRODUCT, they don't generally work in tuple-wise array functions. Your best bet here is to come up with a custom function.
UPDATE
You're question got me thinking about how to handle discontinuous ranges. It's not something I've had to deal with much in the past. I didn't have the time to give a better answer when you asked the question but now that I've got a few minutes, I've whipped up a custom function that will do what you want:
Function gvSUMPRODUCT(ParamArray rng() As Variant)
Dim sumProd As Integer
Dim valuesIndex As Integer
Dim values() As Double
For Each r In rng()
For Each c In r.Cells
On Error GoTo VBAIsSuchAPainInTheAssSometimes
valuesIndex = UBound(values) + 1
On Error GoTo 0
ReDim Preserve values(valuesIndex)
values(valuesIndex) = c.Value
Next c
Next r
If valuesIndex Mod 2 = 1 Then
For i = 0 To (valuesIndex - 1) / 2
sumProd = sumProd + values(i) * values(i + (valuesIndex + 1) / 2)
Next i
gvSUMPRODUCT = sumProd
Exit Function
Else
gvSUMPRODUCT = CVErr(xlErrValue)
Exit Function
End If
VBAIsSuchAPainInTheAssSometimes:
valuesIndex = 0
Resume Next
End Function
Some notes:
Excel enumerates ranges by column then row so if you have a continuous range where the data is organized by column, you have to select separate ranges: gvSUMPRODUCT(A1:A10,B1:B10) and not gvSUMPRODUCT(A1:B10).
The function works by pairwise multiplying the first half of cells with the second and then summing those products: gvSUMPRODUCT(A1,C3,L2,B2,G5,F4) = A1*B2 + C3*G5 + L2*F4. I.e. order matters.
You could extend the function to include n-wise multiplication by doing something like gvNSUMPRODUCT(n,ranges).
If there are an odd number of cells (not ranges), it returns the #VALUE error.
Note that sumproduct(a, b) = sumproduct(a1, b1) + sumproduct(a2, b2) where range a is split into ranges a1 and a2 (and similar for b)
It might be helpful to create an intermediate table that summarizes the data that you are using to calculate the sum product. That would also make the calculation easier to follow.