Im not an expert at excel/sheets. I wanted to make a dynamic function that would stop user error by doing all of the work. The function basically uses regex to get the first letters and adds a number i.e. stell ball = sb01, stell cage = sc01 and so on. My problem grows when I also want to be able to catch multiple entries and potentially offer the next iteration. i.e. stell ball = sb01, stell ball = sb02.
Here is my code ive got working so far:
=COUNTIF(B:B,B1)>1 + CONCAT(ArrayFormula(REGEXREPLACE(proper(A1:A),"[^A-Z]+","")),RIGHT("00"&ROW(A:A),2))
Im getting bogged down with how to iterate the number. Im thinking it needs to be an IF function but Im getting into a super nested problem. In my mind it should be something on the lines of:
=IF(COUNTIF(B:B,B1)>1 + CONCAT(ArrayFormula(REGEXREPLACE(proper(A1:A),"[^A-Z]+","")),RIGHT("00"&ROW(A:A),2)),CONCAT(ArrayFormula(REGEXREPLACE(proper(A1:A),"[^A-Z]+","")),RIGHT("00"&ROW(A:A),+1),"")
try:
=ARRAYFORMULA(IF(A1:A="",,
REGEXREPLACE(PROPER(A1:A), "[^A-Z]+", )&
TEXT(COUNTIFS(A1:A, A1:A, ROW(A1:A), "<="&ROW(A1:A)), "00")))
=ARRAYFORMULA(IF(A1:A="",,
REGEXREPLACE(PROPER(A1:A), "[^A-Z]+", )&
TEXT(COUNTIFS(REGEXREPLACE(PROPER(A1:A), "[^A-Z]+", ),
REGEXREPLACE(PROPER(A1:A), "[^A-Z]+", ), ROW(A1:A), "<="&ROW(A1:A)), "00")))
Related
Apologies if this is a little unclear, or this question has been asked already. It's a little difficult to explain, but I've bolded my question - it's essentially about shortening formulas.
I'm running a payment plan waterfall model. My code works, but, it's er, you know...
IF($K2=Q$1,Assumptions!$E$56*($N2+$O2),IF(AND($K2<Q$1,$M2>Q$1),Assumptions!$E$56*$P2/$L2,0)) + IF(edate($K2,1)=Q$1,Assumptions!$F$56*($N2+$O2),IF(AND(edate($K2,1)<Q$1,edate($M2,1)>Q$1),Assumptions!$F$56*$P2/$L2,0)) + IF(edate($K2,2)=Q$1,Assumptions!$F$56*($N2+$O2),IF(AND(edate($K2,2)<Q$1,edate($M2,2)>Q$1),Assumptions!$F$56*$P2/$L2,0)) + IF(edate($K2,3)=Q$1,Assumptions!$F$56*($N2+$O2),IF(AND(edate($K2,3)<Q$1,edate($M2,3)>Q$1),Assumptions!$F$56*$P2/$L2,0)) + IF(edate($K2,4)=Q$1,Assumptions!$F$56*($N2+$O2),IF(AND(edate($K2,4)<Q$1,edate($M2,4)>Q$1),Assumptions!$F$56*$P2/$L2,0)) + IF(edate($K2,5)=Q$1,Assumptions!$F$56*($N2+$O2),IF(AND(edate($K2,5)<Q$1,edate($M2,5)>Q$1),Assumptions!$F$56*$P2/$L2,0)) + IF(edate($K2,6)=Q$1,Assumptions!$F$56*($N2+$O2),IF(AND(edate($K2,6)<Q$1,edate($M2,6)>Q$1),Assumptions!$F$56*$P2/$L2,0))
...pretty long.
Essentially what's going on is: the assumption is, when we launch a product, we sell say 80% in the first month, and 2.5% every subsequent month until we each 100%.
I'd like the 80% and the 2.5% to be variables (listed as Assumptions!$E$56 and Assumptions!$E$56) here.
Obviously a little long. But noticed after the first IF clause, the subsequent ones are actually identical, the only difference being the number inside edate(__,2), edate(__,3)...
So my question is - can this code be tidied up into some sort of for loop? Python would make it pretty simple to increment over the variable edate(__,i) and sum over i = 1:6.
Sure, there is. Usually looping is emulated by Sequence(N), which makes an array of numbers from [1,N] vertically, which is somewhat like your Python range. Then you can do stuff to it as an ArrayFormula.
In your case, you end up with two terms: your initial term using $E, and all the looped stuff using $F. I see 6 terms, so I will use Sequence(6):
=IF(
$K2=Q$1,
Assumptions!$E$56*($N2+$O2),
IF(
AND(
$K2<Q$1,
$M2>Q$1
),
Assumptions!$E$56*$P2/$L2,
0
)
) + ArrayFormula(SUM(
IF(
edate($K2,SEQUENCE(6))=Q$1,
Assumptions!$F$56*($N2+$O2),
IF(
(edate($K2,SEQUENCE(6))<Q$1)*
(edate($M2,SEQUENCE(6))>Q$1),
Assumptions!$F$56*$P2/$L2,
0
)
)
))
And if you want, you can give your Assumption values names using named ranges.
Wondering if I could get some help with this:
function setupRound()
local gameModes = {'mode 1','mode 2','mode 3'} -- Game modes
local maps = {'map1','map2','map3'}
--local newMap = maps[math.random(1,#maps)]
local mapData = {maps[math.random(#maps)],gameModes[math.random(#gameModes)]}
local mapData = mapData
return mapData
end
a = setupRound()
print(a[1],a[2]) --Fix from Egor
What the problem is:
`
When trying to get the info from setupRound() I get table: 0x18b7b20
How I am trying to get mapData:
a = setupRound()
print(a)
Edit:
Output Issues
With the current script I will always the the following output: map3 mode 2.
What is the cause of this?
Efficiency; is this the best way to do it?
While this really isn't a question, I just wanted to know if this method that I am using is truly the most efficient way of doing this.
First of all
this line does nothing useful and can be removed (it does something, just not something you'd want)
local mapData = mapData
Output Issues
The problem is math.random. Write a script that's just print(math.random(1,100)) and run it 100 times. It will print the same number each time. This is because Lua, by default, does not set its random seed on startup. The easiest way is to call math.randomseed(os.time()) at the beginning of your program.
Efficiency; is this the best way to do it?
Depends. For what you seem to want, yes, it's definitely efficient enough. If anything, I'd change it to the following to avoid magic numbers which will make it harder to understand the code in the future.
--- etc.
local mapData = {
map = maps[math.random(#maps)],
mode = gameModes[math.random(#gameModes)]
}
-- etc.
print(a.map, a.mode)
And remember:
Premature optimization is the root of all evil.
— Donald Knuth
You did very good by creating a separate function for generating your modes and maps. This separates code and is modular and neat.
Now, you have your game modes in a table modes = {} (=which is basically a list of strings).
And you have your maps in another table maps = {}.
Each of the table items has a key, that, when omitted, becomes a number counted upwards. In your case, there are 3 items in modes and 3 items in maps, so keys would be 1, 2, 3. The key is used to grab a certain item in that table (=list). E.g. maps[2] would grab the second item in the maps table, whose value is map 2. Same applies to the modes table. Hence your output you asked about.
To get a random game mode, you just call math.random(#mode). math.random can accept up to two parameters. With these you define your range, to pick the random number from. You can also pass a single parameter, then Lua assumes to you want to start at 1. So math.random(3) becomes actually math.random(1, 3). #mode in this case stand for "count all game modes in that table and give me that count" which is 3.
To return your chosen map and game mode from that function we could use another table, just to hold both values. This time however the table would have different keys to access the values inside it; namely "map" and "mode".
Complete example would be:
local function setupRound()
local modes = {"mode 1", "mode 2", "mode 3"} -- different game modes
local maps = {"map 1", "map 2", "map 3"} -- different maps
return {map = maps[math.random(#maps)], mode = modes[math.random(#modes)]}
end
for i = 1, 10 do
local freshRound = setupRound()
print(freshRound.map, freshRound.mode)
end
I'm currently writing an Addon for World of Warcraft, but I've run a bit of a basic lua problem. The gist of it is, I want to reduce the following elements inside this for loop into a single line.
Currently, I am using WoW's api command of "SetAlpha(0)" (which just hides the frame in game) on a list of frames that share the same name except for the number at the end. ActionButton1Name, ActionButton2Name, ActionButton3Name, etc.
I also have to do the same thing to four other lists, each also having 12 different versions of themselves MultiBarBottomRightButton1Name, MultiBarBottomRightButton2Name, etc.
Essentially, I'd like to take what I currently have:
for i=1, 12 do
["ActionButton"..i.."Name"]:SetAlpha(0)
["MultiBarBottomRightButton"..i.."Name"]:SetAlpha(0)
["MultiBarBottomLeftButton"..i.."Name"]:SetAlpha(0)
["MultiBarRightButton"..i.."Name"]:SetAlpha(0)
["MultiBarLeftButton"..i.."Name"]:SetAlpha(0)
end
SetAlpha is specific to World of Warcraft's API, so disregard that as needed.
And transform it into something where I have all the [ ] elements in their own table somewhere else, and then later use that index
local buttonNameIndex = function()
for i=1, 12 do
["ActionButton"..i.."Name"]
["MultiBarBottomRightButton"..i.."Name"]
["MultiBarBottomLeftButton"..i.."Name"]
["MultiBarRightButton"..i.."Name"]
["MultiBarLeftButton"..i.."Name"]
end
end
for i,v in ipairs(buttonNameIndex) do
v:SetAlpha(0) end
However, the above function didn't seem to work, in that the terminal was spitting out an error of having an unexpected symbol near the do of the 2nd line.
As to why I'd like to do this: I'll be doing a lot more with that list of frames later on, so it'd be nice to have them all combined into a single table.
If these are global variables, use expressions like this:
_G["ActionButton"..i.."Name"]:SetAlpha(0)
which access a global variable from a dynamically created name.
This question already has answers here:
Lua for loop reduce i? Weird behavior [duplicate]
(3 answers)
Closed 7 years ago.
im trying this in lua:
for i = 1, 10,1 do
print(i)
i = i+2
end
I would expect the following output:
1,4,7,10
However, it seems like i is getting not affected, so it gives me:
1,2,3,4,5,6,7,8,9,10
Can someone tell my a bit about the background concept and what is the right way to modify the counter variable?
As Colonel Thirty Two said, there is no way to modify a loop variable in Lua. Or rather more to the point, the loop counter in Lua is hidden from you. The variable i in your case is merely a copy of the counter's current value. So changing it does nothing; it will be overwritten by the actual hidden counter every time the loop cycles.
When you write a for loop in Lua, it always means exactly what it says. This is good, since it makes it abundantly clear when you're doing looping over a fixed sequence (whether a count or a set of data) and when you're doing something more complicated.
for is for fixed loops; if you want dynamic looping, you must use a while loop. That way, the reader of the code is aware that looping is not fixed; that it's under your control.
When using a Numeric for loop, you can change the increment by the third value, in your example you set it to 1.
To see what I mean:
for i = 1,10,3 do
print(i)
end
However this isn't always a practical solution, because often times you'll only want to modify the loop variable under specific conditions. When you wish to do this, you can use a while loop (or if you want your code to run at least once, a repeat loop):
local i = 1
while i < 10 do
print(i)
i = i + 1
end
Using a while loop you have full control over the condition, and any variables (be they global or upvalues).
All answers / comments so far only suggested while loops; here's two more ways of working around this problem:
If you always have the same step size, which just isn't 1, you can explicitly give the step size as in for i =start,end,stepdo … end, e.g. for i = 1, 10, 3 do … or for i = 10, 1, -1 do …. If you need varying step sizes, that won't work.
A "problem" with while-loops is that you always have to manually increment your counter and forgetting this in a sub-branch easily leads to infinite loops. I've seen the following pattern a few times:
local diff = 0
for i = 1, n do
i = i+diff
if i > n then break end
-- code here
-- and to change i for the next round, do something like
if some_condition then
diff = diff + 1 -- skip 1 forward
end
end
This way, you cannot forget incrementing i, and you still have the adjusted i available in your code. The deltas are also kept in a separate variable, so scanning this for bugs is relatively easy. (i autoincrements so must work, any assignment to i below the loop body's first line is an error, check whether you are/n't assigning diff, check branches, …)
I asked a question similar to this the other day, but another bug popped up "attempt to concatenate table and string"
local questions={
EN={
Q2={"Who is the lead developer of Transformice?","Tigrounette"},
Q4={"What is Eminem's most viewed song on youtube?","I love the way you lie"},
Q6={"What is the cubic root of 27?","3"},
Q8={"What are the first 3 digits of Pi","3.141"},
Q10={"What is the most populated country?","China"},
Q12={"What is the plural of the word 'Person'?","People"},
Q14={"Entomology is the science that studies ...?","Insects"},
Q16={"Who was the creator of the (bot ran) minigame fight?","Cptp"},
Q18={"The ozone layer restricts ... radiation","Ultraviolet"},
Q20={"Filaria is caused by ...","Mosquitos"}
}
local main = questions.EN["Q"..math.random(1,20)].."%s" -- bug here
local current_answer_en = string.gsub(current_question_en,1,2)
What type of object is questions.EN["Q"..math.random(1,20)]? Say random is 15, what type of object is questions.EN["Q6"]? It is a {"What is the cubic root of 27?","3"}, which is a table, which Lua doesn't know how to concatenate with a string ("%s" in your case). If you want to concatenate with the first item of this table, then
local main = questions.EN["Q"..math.random(1,20)][1] .. "%s"
Note however that you will need the "random with step" function that I posted in math.random function with step option?, otherwise you could get that the table EN["Q"..something] is nil (if the random number is an odd number, in the code you posted).
Note sure what you are trying to do with current_question_en but if you are trying to extract the question and answer you could do something like this:
local QA = questions.EN["Q"..math.random(1,20)] -- this is a table
local question, answer = QA[1], QA[2]
The other option is that you build your table like this:
local questions={
EN={
Q2={q="Who is ..?", a="Tigrounette"},
Q4={q="What is ...?", a="I love the way you lie"},
...
}
}
Then you could use
local QA = questions.EN["Q"..math.random(1,20)] -- this is a table
print("The question:", QA.q)
print("The answer:", QA.a)
Not sure what you're trying to do with string.gsub but it does not take integers as 2nd and 3rd args.