Related
I have two columns in a table: column_A with 3 different values a1, a2, a3 and column_B with 5 different values b1, b2, b3, b4, b5. I have to create column_C in Excel based on the following logic -
> if (A=a1)
> if(B=b1 or B=b2)
> output=a1_yes
> else
> output = a1_no
> elseif(A=a2)
> if(B=b3 or B=b4)
> output = a2_yes
> else
> output = a2_no
> elseif(A=a3)
> if(B=b5)
> output = a3_yes
> else
> output = a3_no
Nested if-else makes the logic very complex. Is there any function we could use for simplicity and avoid nested if-else?
Assuming you want to get rid of the nested if-else, I would suggest you use the function Switch instead.
You can concatenate the columns you are validating and provide results based on the possible values.
Given the table below:
Make 1
Model 1
Color 1
Use the formula:
SWITCH(expression,value1,result1,default_or_value2,result2,...)
Example:
=SWITCH(CONCAT(A1,B1),"Make1","a1_yes","Make2","a1_yes","a2_yes")
Reference
SWITCH Formula
I think in such complex cases it is best to create a lookup table and find the required value with the LOOKUP function which works starting from Excel 2007:
=LOOKUP(2,1/((A2=$H$2:$H$9)*(B2=$I$2:$I$9)+(A2=$H$2:$H$9)*(""=$I$2:$I$9)),$J$2:$J$9)
In the case of GS, this formula must be included in the ARRAYFORMULA function.
=ArrayFormula(LOOKUP(2,1/((A2=$H$2:$H$9)*(B2=$I$2:$I$9)+(A2=$H$2:$H$9)*(""=$I$2:$I$9)),$J$2:$J$9))
If you can't create lookup table here will be option without it:
=LOOKUP(2,
1/((A2={"a1","a1","a1","a2","a2","a2","a3","a3"})
*(B2={"","b1","b2","","b3","b4","","b5"})
+(A2={"a1","a1","a1","a2","a2","a2","a3","a3"})
*(""={"","b1","b2","","b3","b4","","b5"})),
{"a1_no","a1_yes","a1_yes","a2_no","a2_yes","a2_yes","a3_no","a3_yes"})
I have a dataframe that looks like this (with more rows):
Buy Sell acct_stock usd_account
0 True False
1 False True
I assigned two numerical values to two variables like so:
account = 1000
stock_amount = 0
For each row in the df that has the combination of True AND False, I want to update columns acct_stock and usd_account by using the numerical variables to do calculations:
I have come up with the following FOR loop:
for index,row in df.iterrows():
if (row['Buy'] == True & row['Sell'] == False):
row['acct_stock'] = (account * 0.02)/row[4]
row['usd_account'] = account - (stock_amount * 0.02)
When I run this the columns acct_stock and usd_account do not get updated at all, even for rows where the conditions are met.
What am I doing wrong that the calculations are not being assigned by index to the columns/rows in question and the variables 'account' and 'stock_amount' are also being updated continously?
The answer of why is didn't work is included in this page, The code you need to look at is here
However keep in mind you need to have those column first before you can set a value
I have a DataFrame as shown in the attached image. My columns of interest are fgr and fgr1. As you can see, they both contain values corresponding to years.
I want to iterate in the the two columns and for any value present, I want 1 if the value is present or else 0.
For example, in fgr the first value is 2028. So, the first row in column 2028 will have a value 1 and all other columns have value 0.
I tried using lookup but I did not succeed. So, any pointers will be really helpful.
Example dataframe
Data:
Data file in Excel
This fill do you job. You can use for loops aswell but I think this approach will be faster.
df["Matched"] = df["fgr"].isin(df["fgr1"])*1
Basically you check if values from one are in anoter column and if they are, you get True or False. You then multiply by 1 to get 1 and 0 instead of True or False.
From this answer
Not the most efficient, but should work for your case(time consuming if large dataset)
s = df.reset_index().melt(['index','fgr','fgr1'])
s['value'] = s.variable.eq(s.fgr.str[:4]).astype(int)
s['value2'] = s.variable.eq(s.fgr1.str[:4]).astype(int)
s['final'] = np.where(s['value']+s['value2'] > 0,1,0)
yourdf = s.pivot_table(index=['index','fgr','fgr1'],columns = 'variable',values='final',aggfunc='first').reset_index(level=[1,2])
yourdf
I constantly am tasked with pulling information from another source and receive the information without Size denomination. The size or count is in the description and want to be able to write an excel formula with the following logic:
if cell contains Capsules, Tablets, Liquid, etc, then make this cell equal too Capsules, Tablets, Liquid, etc + the number that comes before it
A few example items:
Nature's Bounty Magnesium 500 mg, 200 Tablets
Aerobic Life Mag 07 Oxygen Digestive System Cleanser Capsules, 180 Count
Natural Vitality Natural Calm Anti Stress Drink 30 count Raspberry Lemon
Want the following column to have Tablets or Count if it is said in the description.
I've tried using if and then statements but don't know how to combine them to create 'or' and 'and'
Expect to have the columns from the examples above to look as follows:
200 Tablets
180 Count
30 Count
If the values are in column A, the formula would be like that:
=+IF(ISERROR(VALUE(RIGHT(LEFT(A3,SEARCH(IF(ISERROR(SEARCH("Tablets",A3)),IF(ISERROR(SEARCH("Capsules",A3)),IF(ISERROR(SEARCH("Count",A3)),"","Count"),"Capsules"),"Tablets"),$A3)-1),4))),0,VALUE(RIGHT(LEFT(A3,SEARCH(IF(ISERROR(SEARCH("Tablets",A3)),IF(ISERROR(SEARCH("Capsules",A3)),IF(ISERROR(SEARCH("Count",A3)),"","Count"),"Capsules"),"Tablets"),$A3)-1),4)))&" "&IF(ISERROR(SEARCH("Tablets",A3)),IF(ISERROR(SEARCH("Capsules",A3)),IF(ISERROR(SEARCH("Count",A3)),"","Count"),"Capsules"),"Tablets")
As the formula is long see below separated in two different cells, the first one search which is the item we are looking (Tablets, Capsules or Count) and returns it, the second one search the previous number:
+IF(ISERROR(SEARCH("Tablets",A4)),IF(ISERROR(SEARCH("Capsules",A4)),IF(ISERROR(SEARCH("Count",A4)),"","Count"),"Capsules"),"Tablets")
+IF(ISERROR(VALUE(RIGHT(LEFT(A4,SEARCH(B4,$A4)-1),4))),0,VALUE(RIGHT(LEFT(A4,SEARCH(B4,$A4)-1),4)))
The formula has a limitation regarding the numbers is getting, and it's limited to 9999, more than that the formula trunks the result. Also for number 1 to 9 the formula may return error #value. This can be addressed changing the second formula if needed.
I would do something like this:
Start with an IF statement IF(-test-, -true-, -false-)
Populate the -test- portion. Say I first wanted to find 'Tablet'. I could use ...FIND("Tablet",A2)... However, the issue here is if "Tablet" is not found it will throw an error so I would error-proof it like this ...IFERROR(Find("Tablet",A2), FALSE)... which will return FALSE if "Tablet" is not found in cell A2.
But I also want to look for 'Count' so I could use an OR along with that I already built up ...OR( IFERROR(Find("Tablet",A2), FALSE), IFERROR(Find("Count",A2), FALSE) ) so this will OR together the outcomes - if either "Tablet" or "Count" is found, this function returns a number (and since it's a number, it's read as TRUE!)
Now I throw that OR() equation into my IF for the -true-, then of course my I could make as "Tablet" or "Count" or put a new equation there to specifically say what it found. And my -false- I can make ""
At this point, I would have a complete equation which will check for "Count" or "Tablet" and spit out whatever is in my -true- equation. Otherwise, the cell would remain blank:
IF(OR( IFERROR(Find("Tablet",A2), FALSE), IFERROR(Find("Count",A2), FALSE) ), "Count/Tablet", "")
Here's a lightly-tested UDF using RegExp:
Function Amounts(txt)
Dim re As Object, allMatches, m, rv, sep
Set re = CreateObject("VBScript.RegExp")
re.Pattern = "(\d+\s?(tablets|tablet|count|liquid))"
re.ignorecase = True
re.MultiLine = True
re.Global = True
Set allMatches = re.Execute(txt)
For Each m In allMatches
rv = rv & sep & m
sep = ","
Next m
Amounts = IIf(rv <> "", rv, "(none)")
End Function
Usage:
=Amounts(A2)
I'm a teacher and trying to create a mark sheet the problem I have is that assignments are marked using different schemes (i.e. % [1 - 100], Level [1 -4], Letter Grade [F - A]). The problem I have is that I only want to report using one marking scheme and need to convert or calculate the other marking schemes based on the scheme there is it is marked.
I've made an excel worksheet which contains a student names and assignments. The sheet then has 3 other columns, one representing each scheme "Letter", "Level", Percentage a column for each scheme. Now, at any given time there is going to be a value in one of the 'scheme' columns - I need excel to automatically or by macro calculate the appropriate value into the other cells.
For example, there are three assignments each marked with a different scheme on the same sheet.
Assignment 1 - %
Assignment 2 - Level
Assignment 3 - Letter Grade
How can I get excel to check which mark value exists and then populate/calculate the other two the corresponding values.
Mike got 80% (%) on Assignment 1, but I want excel to populate the level column and letter column with the corresponding values at the same time Level 3 on Assignment 2 excel to calculate corresponding percentage and letter and at the same time for a Letter A on Assignment 3 the corresponding % and level should be calculated.
Don't know if this is possible or makes sense, but I tried VLOOKUP and was not successful because I have to do it all manually - I'm aiming for an automated process.
Sorry if it is not clear or confusing...but I've been at this for two days with no luck and not even sure if what I'm doing is possible.
of course it should be first assessed the translation of one rating system to the other and then assume those algorithms to shift between rating grades types
one of the possible approaches could be the following:
Option Explicit
Sub main()
Dim grades As Variant, levels As Variant
Dim cell As Range
Dim index As Double
grades = Array("F", "E", "D", "C", "B", "A")
levels = Array(1, 2, 3, 4)
For Each cell In Intersect(Range("A:C"), ActiveSheet.UsedRange).Offset(1).SpecialCells(xlCellTypeConstants)
Select Case cell.Column
Case 1 '%
index = cell.value / 100
cell.Offset(, 1).value = GetRate(index, levels)
cell.Offset(, 2).value = GetRate(index, grades)
Case 2 ' Level
index = InStr(Join(levels, ""), cell.value) / Len(Join(levels, ""))
cell.Offset(, -1).value = index * 100
cell.Offset(, 1).value = GetRate(index, grades)
Case 3
index = InStr(Join(grades, ""), cell.value) / Len(Join(grades, ""))
cell.Offset(, -2).value = index * 100
cell.Offset(, -1).value = GetRate(index, levels)
End Select
Next
End Sub
Function GetRate(index As Double, rates As Variant)
GetRate = rates(WorksheetFunction.Max(Round(index * (UBound(rates) - LBound(rates) + 1), 0) - 1, 0))
End Function
due to the simplicity of the translation algorithm it doesn't provide a bijective relationship between grading systems with different spans, but it can get you closer to your goal
Create a table like so (you can add more rows if you need to define +/- scores like "B+", etc.). The key here is sort the table ascending by %, with each row being the minimum score needed for the corresponding Level/Letter Grade.
Then, you can use VLOOKUP formula against this table, like so to get the Level:
=VLOOKUP(F2,$A$1:$C$7,2,TRUE)
And like so, to get the Letter Grade:
=VLOOKUP(F2,$A$1:$C$7,3,TRUE)
This takes advantage of the True parameter in the VLOOKUP function, which will return an approximate match (and assumes data is sorted ascending). So, when you enter a value like "81%", it returns the nearest row which is not greater than 81%, so it will return data from row 5. Likewise, 12% will return data from row 2, 75% from row 4, etc.
And your results:
You may need to use two tables if you can't 1:1 map the Level/Letter Grade to a Percent row, but the idea would be the same.