Equivalent of excel VBA array and loop in Openpyxl - excel

I have been working with excel VBA. I have created a script for comparing the current week's data with the previous week's data and take some actions based on that comparison. This is the code used by me which runs really very efficiently.
arrc = currWs.Range("A1").CurrentRegion 'outer loop array from currWs
arrp = prevWs.Range("A1").CurrentRegion 'inner loop array from prveWs
For y = 1 To UBound(arrc, 1)
For z = 1 To UBound(arrp, 1)
If arrc(y, 5) = arrp(z, 5) Then
currWs.Range("I" & y).Value = "matched"
Exit For
End If
Next z
Next y
I want to replicate the same in python / openpyxl.
(1) Is there a way we can assign a range of values to a python list as given in the vba program? can it be done in a single statement without a loop?
(2) I would also need in python the equivalent of the outer/inner loops given above
As I have to deal with two sets of 300000 rows, the code needs to be efficient.

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)

Calculating expectation in table - With variable number of entries

Whilst I can correctly calculate Expectation in Excel, I am unsure of how to do so across a table when the number of entries is an unknown.
Currently, I am using the following formula which works: This is the example for 3 Entries,
=R11+(1-R11)*R12+((1-R11)*(1-R12)*R13).
I am using the large formula, to rank my percentages which go into R column but I am having to manually create the code for each subsequent entry and it is getting rather large. For example, the formula for 10 entries is :
=R11+(1-R11)*R12+((1-R11)*(1-R12)*R13)+((1-R11)*(1-R12)*(1-R13)*R14)+((1-R11)*(1-R12)*(1-R13)*(1-R14)*R15)+((1-R11)*(1-R12)*(1-R13)*(1-R14)*(1-R15)*R16)+((1-R11)*(1-R12)*(1-R13)*(1-R14)*(1-R15)*(1-(R16))*R17)+((1-R11)*(1-R12)*(1-R13)*(1-R14)*(1-R15)*(1-(R16))*(1-R17)*R18)+((1-R11)*(1-R12)*(1-R13)*(1-R14)*(1-R15)*(1-(R16))*(1-R17)*(1-R18)*R19)+((1-R11)*(1-R12)*(1-R13)*(1-R14)*(1-R15)*(1-(R16))*(1-R17)*(1-R18)*(1-R19)*R20)
Now, this is actually working. the issue is I would like to find a way to apply this in a table without re-ranking (or ranking this formulaically)
However, I'm not sure how this could be done. I have tried the sumproduct method, but it doesn't apply well to tables with a variable number of inputs, and I am well aware that I am running out of room past 10 entries.
I'm usually a dab hand with Excel - but this has truly got me stumped.
You can use this:
Function lkjlkj(rng As Range) As Double
Dim arr()
arr = rng.Value2
Dim i As Long
For i = 1 To UBound(arr, 1)
Dim temp As Double
temp = arr(i, 1)
Dim j As Long
For j = 1 To i - 1
temp = temp * (1 - arr(j, 1))
Next j
lkjlkj = lkjlkj + temp
Next i
End Function

How to write basic macro to compare two columns for a difference within .50?

I'm trying to write a macro that compares the differences between values in columns B and C. I'd like the macro to compare the two columns (B & C) and find depths that are within +/- .50 of each other, and I'd like to keep track of the sample # (column A) that corresponds to the sample depth that is within +/- .50 of the test depth, and then to find the difference between the sample depth and test depth. For example, the following images are before and after what I'd like the macro to look like:
Before:
After:
here you go. nested loop for the read, iterator to count the output row. May need some customization, but this is the core of it.
Sub foo()
Dim itr As Integer
itr = 2
For Each sd In Range("B:B")
If sd.Value = "" Then Exit For
If IsNumeric(sd.Value) Then
For Each td In Range("C:C")
If td.Value = "" Then Exit For
If IsNumeric(td.Value) Then
If Abs(sd.Value - td.Value) < 0.5 Then
Cells(itr, 5) = sd.Value
Cells(itr, 6) = td.Value
Cells(itr, 8) = sd.Value - td.Value
itr = itr + 1
End If
End If
Next td
End If
Next sd
End Sub

How to reference cell "A(x.Value)" where x is an Integer that goes from 1 until "A(x.Value)" = NULL

I am trying to run through a column in an Excel sheet and search through column A until it finds the first cell that is empty in column A. I need to do it by using a variable x, where x starts at 1 and increases after each run of the loop.
Ideally, I would like to do something like:
Workbooks("Name1").Sheets(2).Range("A.(x.Value)")
but I do not think this will work and am not sure how to do this correctly as I am not too familiar with VBA. Wondering if anyone can help me out with a way to do this, if it is even possible. I have the loops created that I need, I am only having difficulties referencing the cell defined by an integer.
Here is a piece of what I have set up:
Dim x As Integer
Dim y As Integer
Dim z As Integer
Dim status As Boolean
x = 13
y = 2
z = 2
If Workbooks("Training_TEST").Sheets(2).Range("A(x.Value)") = Null Then
status = False
Else
status = True
End If
Integers are not Objects in VBA.
If Workbooks("Training_TEST").Sheets(2).Range("A" & x) = Null Then
You should watch Excel VBA Introduction video series on YouTube.
Here are some relevant videos:
Excel VBA Introduction Part 8 -
Variables
Excel VBA Introduction Part 9 - Object
Variables
Excel VBA Introduction Part 5 - Selecting Cells (Range, Cells,
Activecell, End,
Offset)

Pass from multidimensional array to spreadsheet

I have a multidimensional array which of the form:
where each row represents a sheet and each column represents a type of variable.
What I want to do is export the data into a spreadsheet where each row gets stored in a sheet with its columns. (Maybe it could be easier separate the sim multidimensional array into five matrices and then export those together to a spreadsheet) but I don't know if it's the most efficient way.
Here is a image of the spreadsheet:
Below is my code, which basically reads the sheets from a Excel and make a simulation of 1,000 cases for each type of data:
sim={};
for k = 1 : 5
sheet = xlsread('CB.xlsx', k);
[m, n] = size(sheet)
for i = 1 : n
[f,x] = ecdf(sheet(:,[i]));
[f, dup] = unique(f);
x = x(dup);
randomValues = rand(1, 1000);
sim{k,i} = round(interp1(f,x, randomValues));
end
end
trying to use Mikhail_Sam'answer I got the follow problems:
`sheet = 1
for i = 1:5
for j = 1:5
xlswrite('filename.xls',sim(:,i,j),sheet,strcat(char(64+j),int2str(1)))
end
sheet = sheet+1;
end`
but it says "Index exceeds matrix dimensions", then I tried this code
sheet = 1
for i = 1:5
for j = 1:size(sheet)
xlswrite('filename2.xls',sim{i,j},sheet,'A1:E1000');
end
sheet = sheet+1;
end
This code write the file ith the 5 sheets but it is filled with the first 5 numbers of each row of the multidimensional array. Then I tried to apply num2cell and run your code but it gives "index exceeds matrix dimension" again
I don't know about 'the most efficient way', but I did it this way:
for example I create 3x3x3 matrix and try to write it to excel:
sheet = 1
for i = 1:3
for j = 1:3
xlswrite(filename,x(:,i,j),sheet,strcat(char(64+j),int2str(1)));
end
sheet = sheet+1;
end
And I got what you want - 3 sheets, and data in rows.
replace 3 at your dimensions. But I have one weak place - I don't remember numeric mechanism in multidimensional arrays - is i is a row in your example, or j... Anyway it's work just take a look at data and replace i - j - : if necessary.
Hope, it helps :)
Finally I figure out how pass from multidimensional array to each spreadsheet. I decided to arrange the data in the same multidimensional array to then pass the data to a spreadshe, using A{k}=transpose(vertcat(simulado{k,:})) and then apply a for loop to add the data to each sheet separately.
sheet = 1
for i = 1:5
xlswrite('filename.xls',A{1,i},sheet);
sheet = sheet+1;
end`

Resources