Excel to calculate if values in ranges meet certain criteria using VBA - excel

I have two ranges in excel, say:
x | y
------------
5 | -1
46 | -4
2 | 1
67 | -1
22 | 1
6 | 0
34 | 0
7 | -2
I want calculate the sum of the second column for values less than O only if the respective values in the first column is less than 10 (i.e sum(y(i) for i<0 and x(i)<10) . Hence in this case the sum will be -3.

Assuming your headers are in A1:B1 and your data is A2:B9 use this:
=SUMIFS(B2:B9,A2:A9,"<10",B2:B9,"<0")

Try something like
Function calc() AS Integer
Dim sum AS Integer: sum = 0
Dim c AS Range
For Each c In ThisWorkbook.Worksheets(1).Range("A1:A15")
If c.Value < 10 And c.Offset(0, 1).Value < 0 Then
sum = sum + c.Offset(0, 1).Value
End If
Next c
calc = sum
End Function

Related

Pandas, by row calculations with the first value that satisfy condition

I have a dataframe:
df = pd.DataFrame(
[
[10,20,40],
[2,1,26],
[1, 2, 60],
], columns = ['f1', 'f2', 'f3']
)
df['cumsum'] = df.sum(axis=1)
df['cumsum_perc'] = (df['cumsum'] * 0.1).astype(int)
| | f1 | f2 | f3 | cumsum | cumsum_perc |
|---:|-----:|-----:|-----:|---------:|--------------:|
| 0 | 10 | 20 | 40 | 70 | 7 |
| 1 | 2 | 1 | 26 | 29 | 2 |
| 2 | 1 | 2 | 60 | 63 | 6 |
As you can see, for each row I have calculated cumulative sum, and than out of cumulative sum an arbitrary (in this case 10%) percentage of the cumulative sum.
Each f column has its ponder value (f_pon), f1 = 1, f2 = 2, f3 = 3.
Now, for each row, I have to find out f column with highest value, whose value is less or equal then cumsum_perc (f_le) in order to determine its f_pon.
Let's consider the third row, for an example.
f_le = f2 (2 < 6), which implies f_pon = 2.
Now I have to see is there any reminder in cumsum_perc - f_le column.
rem = cumsum_perc (6) - f_le (2) = 4.
I have to calculate percentage of reminder considering the value of the first f column to the right of f_le (f3), so here we have rem_perc = rem (4) / f3 (60) = 0.066.
Final result for the third row is f_pon (2) + rem_perc = 2.066.
If we apply the same logic for the first row, than f1 is f_le, and there is no reminder because cumsum_perc (7) - f_le (10) = -3. If rem is negative it should be set to 0.
So result is f1_pon (1) + rem (0) / f2 (20) = 1
For second row, the result is also 1, because there is no reminder.
How to calculate final results for each row in the most efficient way?
To be honest it is difficult to follow your rules, but since you now your rules, I suggest to implement a helper function and use df.apply(helper, axis=1) row wise.
This might not be the fastest implementation, but at least you get you results.
def helper(x):
basic_set = x[['f1','f2','f3']]
cumsum_perc = x['cumsum_perc']
f_pon = basic_set[basic_set<cumsum_perc].max()
rem = cumsum_perc - f_pon
if not rem:
rem = 0
rem_perc = rem / x['cumsum']
if not rem_perc:
rem_perc = 0
return f_pon + rem_perc
df['ans'] = df.apply(helper, axis=1)
>>> df
f1 f2 f3 cumsum cumsum_perc ans
0 10 20 40 70 7 NaN
1 2 1 26 29 2 1.034483
2 1 2 60 63 6 2.063492
I think you can adapt the helper, if mine is wrong.

Coding string to numeric in Excel

I want to convert string codes to integer codes
Here is my Excel file
Level1 Level2 Level3 Level4 Time1 Time2 Time3 Time4
A B E C 12 14 12 13
D D E C 11 17 16 9
E C C B 14 13 19 8
C E B D 11 12 10 7
B A A D 10 11 7 6
A= 4, B=3, C=2, D=1 , E= 0
get this in sheet2
Level1 Level2 Level3 Level4 Time1 Time2 Time3 Time4
4 3 0 2 12 14 12 13
1 1 0 2 11 17 16 9
0 2 2 3 14 13 19 8
2 0 3 1 11 12 10 7
3 4 4 1 10 11 7 6
Is it possible?
Use the ASCII table and some basic maths.
dim i as long
for i=65 to 69
worksheets("sheet1").cells.replace what:=chr(i), replacement:=(69-i)
next i
This isn't as fast as a dictionary, but its clocking at 1 second for 10,000 rows across 4 columns.
Searching in columns A - D down to last row (determined by Col A)
Dim ws As Worksheet: Set ws = ThisWorkbook.Sheets("Sheet1")
Dim SearchRange As Range: Set SearchRange = ws.Range("A2:D" & ws.Range("A" & ws.Rows.Count).End(xlUp).Row)
Application.ScreenUpdating = False
SearchRange.Replace What:="A", Replacement:=4, LookAt:=xlWhole
SearchRange.Replace What:="B", Replacement:=3, LookAt:=xlWhole
SearchRange.Replace What:="C", Replacement:=2, LookAt:=xlWhole
SearchRange.Replace What:="D", Replacement:=1, LookAt:=xlWhole
SearchRange.Replace What:="E", Replacement:=0, LookAt:=xlWhole
Application.ScreenUpdating = True
Set up an area of any worksheet (for example Sheet2) with your chosen mapping of letters to numbers, like this:
+--------+-------+
| Letter | Value |
+--------+-------+
| A | 4 |
| B | 3 |
| C | 2 |
| D | 1 |
| E | 0 |
+--------+-------+
Then, suppose on one of your main worksheets you have a letter in cell B3="D". You can enter a formula into a different cell, perhaps cell C3, with your lookup formula: =VLOOKUP(B3,Sheet2!A2:B10,2,FALSE). (The range A2:B10 in this case would be replaced with the range of your entire letter-to-number table). The formula will return the number value.
Enter this in Sheet2!A2
=IF(ISNUMBER(Sheet1!A2),Sheet1!A2,69-CODE(Sheet1!A2))
Fill over/down as needed.

Sum odd cell values if even cells are not empty

I have the following data:
4 | | 1 | 2 | | | 2 | 3
I want to sum odd values when the following even cell is not empty.
So my sum must be: 1 + 2 = 3
I use this formula:
=SUMPRODUCT((MOD(COLUMN(F2:BE2);2)=0)*F2:BE2)
It obviously gives: 4 + 1 + 2 = 7
How can I change the formula to get the 1st result?
Try this:
=SUMPRODUCT((MOD(COLUMN(E2:BD2);2)=1)*(F2:BE2<>"")*(E2:BD2))

Shuffle values to a new row two cells at a time

To explain it in the easiest way possible:
| 1 | 2 | 3 | 4 |
| 5 | 6 | 7 | 8 |
... needs to look like:
| 1 | 2 |
| 3 | 4 |
| 5 | 6 |
| 7 | 8 |
I've tried using the TRANSPOSE() function, but it doesn't seem to work in this situation.
How can I accomplish this simple task?
In an unused cell to the right use this formula,
=OFFSET($A$1, INT((ROW(1:1)-1)/2), COLUMN(A:A)-1+MOD((ROW(1:1)-1), 2)*2)
Fill right one column and fill down as far as necessary. Your results should resemble the following.
      
You put excel-vba in your tags, so I'll post the vba code for you. I don't know how to do it with simple cell formulas. Hopefully it's configurable enough to get what you want, beyond the simple example you gave:
START_ROW = 1
START_COL = 1
STEP_COL = 2
OUTPUT_ROW = 3
OUTPUT_COL = 10
Row = START_ROW
Col = START_COL
Out_Row = OUTPUT_ROW
While Cells(Row, Col).Value <> ""
While Cells(Row, Col).Value <> ""
For step = 0 To STEP_COL - 1
Cells(Out_Row, OUTPUT_COL + step).Value = Cells(Row, Col + step).Value
Cells(Out_Row, OUTPUT_COL + step).Value = Cells(Row, Col + step).Value
Next step
Out_Row = Out_Row + 1
Col = Col + STEP_COL
Wend
Col = START_COL
Row = Row + 1
Wend

Get a Sum of ONLY duplicate values

If there a way to use a sumif combined with a countif?
for example if I have
TransactionNo|NumberToSum
1 |
1 | 9
2 | 6
3 | 3
4 |
4 | 4
5 | 6
6 | 4
7 |
7 | 9
8 | 7
9 | 4
10 |
10 | 1
11 | 3
12 | 6
My result would be: 23
because the values 1,4,7,10 are duplicated, so I need to sum the NumberToSum of those 9,4,9,1 in this case.
Ideally I would like somethings along the lines of =SumIf(A:A,Count>1,B:B)
Where B is summed if the count of A inside of A:A is > 1.
but =SUMIF(A:A,COUNT(A:A)>1,B:B) does not work.
NOTE: the Data is NOT sorted as it appears in my example.
If I wanted to do it in VBA one quick way could be:
Sub sumdups()
Dim rng As Range
Dim rng2 As Range
Dim Sum As Long
Set rng = [A2:A17]
For Each rng2 In rng
If WorksheetFunction.CountIf(Range("A1:A17"), rng2.Value) > 1 Then
Sum = Sum + rng2.Offset(0, 1).Value
End If
Next rng2
End Sub
Another option I have tried is to add a column with the formula
=IF(COUNTIF(A:A,A2)>1,B2,"")
Then sum the helper column, but I am hoping there is a simple formula that can do the same all in one cell.
I am really just looking for a faster formula that can be entered in a single cell, without the need for any additional calculations.
This formula works for me:
=SUMPRODUCT(1*(COUNTIF(A1:A100,A1:A100)>1),(B1:B100))
or for entire column (a little bit slower):
=SUMPRODUCT(1*(COUNTIF(A:A,A:A)>1),(B:B))

Resources