Who owes who money algorithm in excel spreadsheet - excel

I have a group of people who have different expenses during a period. Everybody has a balance after this period. It looks like this in excel:
Person A: 6
Person B: 10
Person C: -7,5
Person D: -8,5
After this period a settlement will take place. I currently do this by manually. This results in:
Person C pays 6 to person A.
Person C pays 1,5 to person B.
Person D pays 8,5 to person B.
Person A gets 6 from person C.
Person B gets 1,5 form person C.
Peron B gets 8,5 from person D.
(There are multiple solutions possible when more persons are involved.)
The problem is that I have to apply this procedure for a big group of people. So my question is: 'How to apply this 'who owes who'-procedure by using an excel spreadsheet algorithm or macro?'.

I made a excel version too but its in Open office. can you download that? The following macro might work on its own. If it does not should be something small. it works fine in OOO and is saved as a Excel 97/2000 workbook document.
'this might not be needed in Microsoft Excel, comment it out
Option VBASupport 1 'OWES
Option Explicit
'Cells(row, col),
Private Sub cmd1_Click()
'data is same sheet, from row 4, column 4
'row 4 has names in columns, so 4,4 has name 1, 4,5 has name 2
'row 5 has amounts spent like 6, -10
'output is in columns 3 and 5
dim i
dim j,s as String, sum1
s=""
'get number of cells used in row 4 and check if corresponding row 6 column has a number value too
i = 4
sum1=0
do while(cells(4,i).Value <> "" and i < 500)
j = CDbl(cells(5,i).Value)
sum1 = sum1 + j
if j <> cells(5,i).Value then
MsgBox "Col " & i & " not a number?"
End
end if
i=i+1
loop
if i > 499 then
Msgbox "too many cols"
End
end if
If sum1 > 0.3 or sum1 < -0.3 then
Msgbox "Sum is not near 0 :" & sum1
End
End if
Dim colCnt as Integer
colCnt = i - 4
cells (7,1).Value = "Col count = " & colCnt
Dim spent(colCnt) as Double
Dim owes1(colCnt ) as String
Dim owes2(colCnt ) as String
for i= 4 to colCnt + 3
spent(i - 3) = CDbl(cells(5,i).Value)
Next
Dim cnt,lastNeg, abs1,maxPay ' safety var for never ending loops, only if data bad like many cols and more than .1 diffs
lastNeg = 4
dim lastPay1
lastPay1 = 10
dim ii,jj,c1,c2,toPay
toPay = 0
On Local Error Goto errh
for i= 4 to colCnt + 3
cnt = 0
ii = i - 3
c1 = spent(ii)
'Cells(6,i) = "ok "
if spent(ii) > 0.1 and cnt < colCnt Then '//has to take
cnt = cnt + 1
for j = lastNeg to colCnt + 3 ' ; j < people.length && spent(ii) > 0.1; j++)
jj = j - 3
's = s & Me.Cells(ii,j) & " "
if spent(ii) > 0.1 then
if spent(jj) < -0.1 Then ' //has to give and has balance to give
c1 = spent(ii)
c2 = spent(jj)
lastNeg = j
abs1 = spent(jj) * -1'//can use absolute fn
maxPay = abs1
if(maxPay > spent(ii)) Then
toPay = spent(ii)'
else
toPay = abs1
End if
spent(ii) = spent(ii) - toPay
spent(jj) = spent(jj) + toPay
Cells(lastPay1, 3).Value = Cells(4 , j) & " pays " & toPay & " to " & Cells(4 , i )
Cells(lastPay1, 5).Value = Cells(4 , i) & " gets " & toPay & " from " & Cells(4 , j)
lastPay1 = lastPay1 + 1
End if
End if
Next
End if
Next
Msgbox "Done"
err.Clear
if err.Number <> 0 Then
errH:
dim yy
yy = msgBox("err " & err.Number & " " & err.Description & " Continue", 2)
if yy = vbYes Then
Resume Next
End IF
End IF
End Sub
Book at http://sel2in.com/prjs/vba/profile (owes)
Can see http://www.excel-vba.com/ , http://office.microsoft.com/en-in/training/get-in-the-loop-with-excel-macros-RZ001150634.aspx the help in excel was useful too (f1 inside macro editor, can select a keyword or type and get context sensitive help by pressing f1)

How important is the pairing of who owes what to who? The reason I ask - it's simple to figure out the total cost per person and then determine who owes money and who needs a refund. If one person can be the "banker", he can collect all the money due and disburse all the refunds.
Much simpler question, if you have somebody willing to be the banker.
Trying to pair everything up will quite possibly not result in an exact answer, or may require one or more people making payments to more than one person - as well as one or more people trying to collect from more than one other person.

See http://sel2in.com/pages/prog/html/owes.html
Javascript fn
<form>
Paste tab seperated list of people on first line, Second line has blanace - positive means they spent more than others, negative means other spent on them (they owe)
<br>
<textarea id=t1 rows=3 cols=70></textarea>
</form>
<button onclick=calcOwes() >Calc owes</button>
<br>
<b>Result:</b>
<div id=result>Will appear here if data is good</div>
<br>
<b>Parsed data for debug:</b>
<div id=data1>Will appear here if data is good</div>
<br>
<hr>
<script>
function calcOwes(){
/**
2013 Tushar Kapila
If Person A: 6
Person B: 10
Person C: -7,5
Person D: -8,5
Then Person C pays 6 to person A.
Person C pays 1,5 to person B.
Person D pays 8,5 to person B.
*/
s = document.getElementById("t1").value
var line = s.split("\n")
//v = confirm("Your Data looks okay?:\n" + s)
//if(!v){ return;}
if(s.length < 2 || s.indexOf("\n") < 0){
alert("No line sep ")
return
}
people = line[0].split("\t")
spent = line[1].split("\t")
spent2 = line[1].split("\t")
if(spent.length < 2){
alert("Bad data, no spent data " + spent.length + "; 0 " + spent[0] + "; 1 " + + spent[1])
return
}
if(people.length != spent.length){
alert("People and amounts do not tally. make sure no tabs inside names, spaces are okay")
return
}
sum = 0;
data1o = document.getElementById("data1")
data1o.innerHTML = "";
for(i = 0;i < people.length; i++){
spent[i] = spent[i].trim()
spent[i] = parseFloat(spent[i])
sum += spent[i]
s = (1 + i) + " \"" + people[i] + "\" :" + spent[i] + ";<br>"
data1o.innerHTML += s;
}
if(sum > 0.2 || sum < -0.2){
v = confirm("Sum (" + sum + ")is not zero continue?")
if(!v){return;}
}
lastNeg = 0;
payDetails = new Array();
getDetails = new Array();
lastPay = 0;
for(i = 0;i < people.length; i++){
cnt = 0;
if(spent[i] > 0.1 && cnt < people.length){//has to take
cnt++
for(j = lastNeg; j < people.length && spent[i] > 0.1; j++){
if(spent[j] < -0.1){//has to give and has balance to give
lastNeg = j;
abs1 = spent[j] * -1;//can use absolute fn
maxPay = abs1
if(maxPay > spent[i]){
toPay = spent[i];
}else{
toPay = abs1
}
spent[i] -= toPay
spent[j] += toPay
payDetails[lastPay] = people[j] + " pays " + toPay + " to " + people[i]
getDetails[lastPay] = people[i] + " gets " + toPay + " from " + people[j]
lastPay++;
}
}
}
}
s = ""
s2 = ""
for(i = 0;i < lastPay; i++){
s = s + payDetails[i] + "<br>"
s2 = s2 + getDetails[i] + "<br>"
}
document.getElementById("result").innerHTML = s + "<br>" + s2
}
</script>
<br>Sample input 1 (tabs there?)
<br><pre>
a b c d
6 10 -7.5 -8.5
</pre>
<br>Sample input 2
<pre>
Anna Dan Bobby Scareface Colly Doc Egg face
-6 10 -7.3 -8.33 11.67
</pre>

Related

Pandas stock dataframe , initialize a counter in a columns on a condition met (ORB, NR4/7)

I have some code which downloads stock price data from Yahoo finance. I want to create some sort of distribution statistics for so called "narrow ranges in a given time period - (which lead to expansion bars). Mostly for the narrowst range in 4 or 7 days. After marking those narrow ranges with 'NR7' or 'NR4' - preferably in only column - I want to start a counter which starts with every 'NR' with 1 and they next day increases by 1 so that´s 2 on the second day, after the 'NR' occured, 3 on the third and so on...
I tried to realize it in the vectorized code for defining a narrow range. Look at the code for df['Bars2NR']. It doesn´t work this way bc it´s self referencing? What options would you prefer to realize a renewed counter on every new 'NR'?
import pandas as pd
import numpy as np
import yfinance
#download stock price time series data
Ticker = 'MSFT'
df = yfinance.download(Ticker , start='2022-01-01', end='2022-09-17' )
#Calculate basic indicators / moving averages
df['SMA10'] = df['Close'].rolling(10).mean()
df['ADR20'] = ((df['High'].rolling(20).mean()/df['Low'].rolling(20).mean())-1)*100
df['ADR1'] = (df['High']/df['Low']-1)*100
df['Range'] = df['High']-df['Low']
df['OCRange'] = abs(df['Open']-df['Close'])
BarFillThreshold = 0.75
df['TrendBar'] = df['OCRange']/df['Range'] > BarFillThreshold
df['Bars2NR'] = 0
#Define narrow range bars (smallest of last 7 or 4 bars)
df['NR7'] = np.where((df.Range < df.Range.shift()) & (df.Range < df.Range.shift(-1))
& (df.Range < df.Range.shift(-2)) & (df.Range < df.Range.shift(-3))
& (df.Range < df.Range.shift(-4)) & (df.Range < df.Range.shift(-5))
& (df.Range < df.Range.shift(-6)), 'NR7', '')
#Narrow Range Bar 4 (in days)
df['NR4'] = np.where((df.Range < df.Range.shift()) & (df.Range < df.Range.shift(-1))
& (df.Range < df.Range.shift(-2)) & (df.Range < df.Range.shift(-3))
, 'NR4', '')
df['Bars2NR'] = np.where((df.Range < df.Range.shift()) & (df.Range < df.Range.shift(-1))
& (df.Range < df.Range.shift(-2)) & (df.Range < df.Range.shift(-3))
& (df.Range < df.Range.shift(-4)) & (df.Range < df.Range.shift(-5))
& (df.Range < df.Range.shift(-6)), 1, df.Bars2NR.shift(1)+2 )' <--- '
#Every time there is a new NR4 or NR7 a new count start with 1 should start
df['RangeExpansion'] =np.where((df.ADR1 > df.ADR20), 1, 0)
df.tail(50)

Replace not working with SAP Gui Scripting retrieved data

So I created a scripting to retrieve data from SAP Gridview object to an Excel sheet. Some columns I needed to replace some characters because this data is consumed by a Power Bi report. For example:
4,350.00 will be replaced for the value 4350. So I do two replaces, the first removing the . and the second replacing the , with .
The problem is that the replace is being applied in every data retrieved. Here's the code.
For i = 0 To GridView.RowCount - 1
For j = 0 To GridView.ColumnCount - 1
shtInput.Cells(z + i, j + 1) = GridView.GetCellValue(i, GridView.ColumnOrder(j))
If j > 8 And j < 19 Then:
rep = GridView.GetCellValue(i, GridView.ColumnOrder(j))
rep = replace(rep, ".", "")
rep = replace(rep, ",", ".")
shtInput.Cells(z + i, j + 1) = rep
Next j
shtInput.Cells(z + i, Area) = "Finance"
If i Mod 32 = 0 Then
GridView.SetCurrentCell i, CStr(Columns(0))
GridView.firstVisibleRow = i
End If
Next i
There's a data column that the script capture the value 21.02.2021 and replace it with 21,02,2021.

VBA convert time on Number

I need to convert my time to Number. i need it because letter i'm going to divide this dates by yourself to calculate % (agent productive time ).
I tried something like this
'cells(2,3) = 22:12:2
cells(2,3) / (60*60*1000)
Thanks in advance
You can do like this:
a = "78:19:41"
b = "74:23:58"
ta = (Split(a, ":")(0) / 24) + TimeValue("00:" & Split(a, ":", 2)(1))
tb = (Split(b, ":")(0) / 24) + TimeValue("00:" & Split(b, ":", 2)(1))
p = tb / ta * 100
p -> 94.9844138434859

Python I am making a calculator for the formula/answer of 3 different things, but 2/3 of the things display with extra characters

PYTHON
I am making a calculator that displays formulas and answers of a few different things after you enter time, distance, mass, etc. Velocity works fine, but Speed and Acceleration are display apostrophes, commas, and parentheses. Some of them aren't even in the editor.
Output:
('Speed = Distance / Time = 1m / 1s', ' = 1m/s')
('Acceleration = Force / Mass = 1N', ' / 1kg = 1.0m/s/s')
Velocity = Speed + Direction = 1m/s + Direction = 1m/s North
The variables in the program:
SpeedFormula = 'Speed = Distance / Time = ' + distanceDisplay + ' / ' + timeDisplay, ' = ' + speedDisplay
AccelerationFormula = 'Acceleration = Force / Mass = ' + forceDisplay, ' / ' + massDisplay + ' = ' + AccelerationDisplay
VelocityFormula = 'Velocity = Speed + Direction = ' + speedDisplay + " + " + 'Direction' + ' = ' + VelocityDisplay
Anyone know why they display differently and how I can fix it?
Replace
timeDisplay, ' = ' + speedDisplay
with
timeDisplay + ' = ' + speedDisplay
When you use comma SpeedFormula becomes a tuple, not a string.
P.S. You should probably use formatting like this:
distanceDisplay = 20
timeDisplay = 2
speedDisplay = 10
SpeedFormula = 'Speed = Distance / Time = %d / %d = %d' % (distanceDisplay,timeDisplay,speedDisplay)

Convert Number to Corresponding Excel Column [duplicate]

This question already has answers here:
How to convert a column number (e.g. 127) into an Excel column (e.g. AA)
(60 answers)
Closed 8 years ago.
I need some help in doing a logic that would convert a numeric value to corresponding MS Excel header value.
For example:
1 = "A"
2 = "B"
3 = "C"
4 = "D"
5 = "E"
.........
25 = "Y"
26 = "Z"
27 = "AA"
28 = "AB"
29 = "AC"
30 = "AD"
.........
Would appreciate some .NET codes (C# or VB) for this. Thanks.
Here's some VBA (with test code) I strung together in Excel which does the trick. Unless VB.NET has changed drastically, it should work okay. Even if it has, you should be able to translate the idea into workable code.
' num2col - translate Excel column number (1-n) into column string ("A"-"ZZ"). '
Function num2col(num As Integer) As String
' Subtract one to make modulo/divide cleaner. '
num = num - 1
' Select return value based on invalid/one-char/two-char input. '
If num < 0 Or num >= 27 * 26 Then
' Return special sentinel value if out of range. '
num2col = "-"
Else
' Single char, just get the letter. '
If num < 26 Then
num2col = Chr(num + 65)
Else
' Double char, get letters based on integer divide and modulus. '
num2col = Chr(num \ 26 + 64) + Chr(num Mod 26 + 65)
End If
End If
End Function
' Test code in Excel VBA. '
Sub main()
MsgBox ("- should be " & num2col(0))
MsgBox ("A should be " & num2col(1))
MsgBox ("B should be " & num2col(2))
MsgBox ("Z should be " & num2col(26))
MsgBox ("AA should be " & num2col(27))
MsgBox ("AB should be " & num2col(28))
MsgBox ("AY should be " & num2col(51))
MsgBox ("AZ should be " & num2col(52))
MsgBox ("BA should be " & num2col(53))
MsgBox ("ZY should be " & num2col(27 * 26 - 1))
MsgBox ("ZZ should be " & num2col(27 * 26))
MsgBox ("- should be " & num2col(27 * 26 + 1))
End Sub
public string ColumnNumberToLetter(int ColumnNumber)
{
if (ColumnNumber > 26)
{
return ((char) (Math.Floor(((double)ColumnNumber - 1) / 26) + 64)).ToString()
+ ((char) (((ColumnNumber - 1) % 26) + 65)).ToString();
}
return ((char)(ColumnNumber+64)).ToString();
}
Try this:
public static string ToExcelString(int number)
{
if (number > 25)
{
int secondaryCounter = 0;
while (number > 25)
{
secondaryCounter = secondaryCounter + 1;
number = number - 25;
}
return ToExcelChar(number) + ToExcelChar(secondaryCounter);
}
else
{
return ToExcelChar(number)
}
}
private const string alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
private static string ToExcelChar(int number)
{
if (number > 25 || number < 0)
{
throw new InvalidArgumentException("the number passed in (" + number + ") must be between the range 0-25");
}
return alphabet[number];
}
Use a number base conversion routine. You want to convert from base 10 to base 26. Add each digit to 'A'
As in: http://www.vbforums.com/showthread.php?t=271359
Just Use the activecell.address then manuipulate the string based on where the $ is to what you need.

Resources