Let me explain, I'm working in a bank and I'm trying to make a short python script that calculates the percentage of different shareholders.
In my example EnterpriseA is owned by different Shareholders directly and indirectly I stored it as it follows :
EnterpriseA = {'Shareholder0': {'Shareholder1': 25, 'Shareholder2': 31, 'Shareholder3': 17, 'Shareholder4': 27},
'Shareholder3': {'Shareholder1': 34, 'Shareholder4': 66}}
I want to calculate how much each shareholders have of EntrepriseA, but I can't figure how to check if a shareholder appears multiple times in all my dictionaries.
What I'm thinking is checking if Shareholder1 appears multiple times if so calculate how many percentage he owns of EnterpriseA like this :
percentage = EnterpriseA['Shareholder0']['Shareholder1'] + (EnterpriseA['Shareholder0']['Shareholder3']*EnterperiseA['Shareholder3']['Shareholder1']/100)
I've made a quick drawing for better understanding
If the maximum depth is only ever singly nested then you can just write a little helper function.
Edit:
From what you've explained, 'Shareholder0' is basically a list of direct enterprise shares.
I've modified the helper function and included a constant reflecting that.
ENTERPRISE_SHARES = 'Shareholder0'
EnterpriseA = {
'Shareholder0': {
'Shareholder1': 25,
'Shareholder2': 31,
'Shareholder3': 17,
'Shareholder4': 27
},
'Shareholder3': {
'Shareholder1': 34,
'Shareholder4': 66
}
}
def calc_percent(enterprise, name):
parent_percents = enterprise[ENTERPRISE_SHARES]
total_percent = parent_percents.get(name, 0)
for shareholder, shares in enterprise.items():
if shareholder != ENTERPRISE_SHARES and shareholder != name:
total_percent += parent_percents[shareholder] / 100 * shares.get(name, 0)
return total_percent
print(calc_percent(EnterpriseA, 'Shareholder1'))
print(calc_percent(EnterpriseA, 'Shareholder2'))
print(calc_percent(EnterpriseA, 'Shareholder4'))
I thought that setting a fixed number of decimal points to all numbers of an array of Decimals, and the new arrays resulting from operations thereof, could be achieved by simply doing:
from decimal import *
getcontext().prec = 5 # 4 decimal points
v = Decimal(0.005)
print(v)
0.005000000000000000104083408558608425664715468883514404296875
However, I get spurious results that I know are the consequence of the contribution of these extra decimals to the calculations. Therefore, as a workaround, I used the round() function like this:
C_subgrid= [Decimal('33.340'), Decimal('33.345'), Decimal('33.350'), Decimal('33.355'), Decimal('33.360'), Decimal('33.365'), Decimal('33.370'), Decimal('33.375'), Decimal('33.380'), Decimal('33.385'), Decimal('33.390'), Decimal('33.395'), Decimal('33.400'), Decimal('33.405'), Decimal('33.410'), Decimal('33.415'), Decimal('33.420'), Decimal('33.425'), Decimal('33.430'), Decimal('33.435'), Decimal('33.440'), Decimal('33.445'), Decimal('33.450'), Decimal('33.455'), Decimal('33.460'), Decimal('33.465'), Decimal('33.470'), Decimal('33.475'), Decimal('33.480'), Decimal('33.485'), Decimal('33.490'), Decimal('33.495'), Decimal('33.500'), Decimal('33.505'), Decimal('33.510'), Decimal('33.515'), Decimal('33.520'), Decimal('33.525'), Decimal('33.530'), Decimal('33.535'), Decimal('33.540'), Decimal('33.545'), Decimal('33.550'), Decimal('33.555'), Decimal('33.560'), Decimal('33.565'), Decimal('33.570'), Decimal('33.575'), Decimal('33.580'), Decimal('33.585'), Decimal('33.590'), Decimal('33.595'), Decimal('33.600'), Decimal('33.605'), Decimal('33.610'), Decimal('33.615'), Decimal('33.620'), Decimal('33.625'), Decimal('33.630'), Decimal('33.635'), Decimal('33.640'), Decimal('33.645'), Decimal('33.650'), Decimal('33.655'), Decimal('33.660'), Decimal('33.665'), Decimal('33.670'), Decimal('33.675'), Decimal('33.680'), Decimal('33.685'), Decimal('33.690'), Decimal('33.695'), Decimal('33.700'), Decimal('33.705'), Decimal('33.710'), Decimal('33.715'), Decimal('33.720'), Decimal('33.725'), Decimal('33.730'), Decimal('33.735'), Decimal('33.740'), Decimal('33.745'), Decimal('33.750'), Decimal('33.755'), Decimal('33.760'), Decimal('33.765'), Decimal('33.770'), Decimal('33.775'), Decimal('33.780'), Decimal('33.785'), Decimal('33.790'), Decimal('33.795'), Decimal('33.800'), Decimal('33.805'), Decimal('33.810'), Decimal('33.815'), Decimal('33.820'), Decimal('33.825'), Decimal('33.830'), Decimal('33.835'), Decimal('33.840'), Decimal('33.845'), Decimal('33.850'), Decimal('33.855'), Decimal('33.860'), Decimal('33.865'), Decimal('33.870'), Decimal('33.875'), Decimal('33.880'), Decimal('33.885'), Decimal('33.890'), Decimal('33.895'), Decimal('33.900'), Decimal('33.905'), Decimal('33.910'), Decimal('33.915'), Decimal('33.920'), Decimal('33.925'), Decimal('33.930'), Decimal('33.935'), Decimal('33.940'), Decimal('33.945'), Decimal('33.950'), Decimal('33.955'), Decimal('33.960'), Decimal('33.965'), Decimal('33.970'), Decimal('33.975'), Decimal('33.980'), Decimal('33.985'), Decimal('33.990'), Decimal('33.995'), Decimal('34.000'), Decimal('34.005'), Decimal('34.010'), Decimal('34.015'), Decimal('34.020'), Decimal('34.025'), Decimal('34.030'), Decimal('34.035'), Decimal('34.040'), Decimal('34.045'), Decimal('34.050'), Decimal('34.055'), Decimal('34.060'), Decimal('34.065'), Decimal('34.070'), Decimal('34.075'), Decimal('34.080'), Decimal('34.085'), Decimal('34.090'), Decimal('34.095'), Decimal('34.100'), Decimal('34.105'), Decimal('34.110'), Decimal('34.115'), Decimal('34.120'), Decimal('34.125'), Decimal('34.130'), Decimal('34.135'), Decimal('34.140')]
C_subgrid = [round(v, 4) for v in C_subgrid]
I got the values of C_subgrid list by printing it out during execution of my code, and I pasted it here. Not sure where the single quotes come from. This code snipped worked fine in Python2.7, but when I upgraded to Python 3.7 it started raising this error:
File "/home2/thomas/Documents/4D-CHAINS_dev/lib/peak.py", line 301, in <listcomp>
C_subgrid = [round(v, 4) for v in C_subgrid] # convert all values to fixed decimal length floats!
decimal.InvalidOperation: [<class 'decimal.InvalidOperation'>]
Strangely, if I run it within ipython it works fine, only within my code it creates problems. Can anybody think of any possible reason?
This is my python file
path = '/my/file/list.txt'
with open(path,'rt') as file:
print("step 1")
collected_lines = []
started = False
for line in file:
for n in range(1, 10):
if line.startswith('PLAY NO.{}'.format(n)):
started = True
print("started at line {}".format(line[0]))
continue
if started:
collected_lines.append(line)
if started and line == 'PLAY NO.{}'.format(n+1):
print("end at line {}".format(line[0]))
break
print(collected_lines.append(line))
This is my code..
OUTPUT:
None
None
None
None
None
None
Now I want the lines starting from play No2 to play No3.... But I am getting None.. Please any suggestions... I am using Python 3.5
Sorry this is the first time asking question on this site..
My file looks like this..
textfile.txt
Hello and Welcome This is the list of plays being performed here
PLAY NO. 1
1. adknjkd
2. skdi
3. ljdij
PLAY NO. 2
1. hsnfhkjdnckj
2. sjndkjhnd and so on
path = 'list.txt'
collected_lines = []
with open(path,'rt') as file:
print("step 1")
started = False
lineNo = 0
for line in file:
lineNo += 1
for n in range(1, 10):
# print('PLAY NO. {}'.format(n))
if started and line.lstrip().startswith('PLAY NO. {}'.format(n)):
print("### end at line {}".format(lineNo))
started = False
break
if line.lstrip().startswith('PLAY NO. {}'.format(n)):
started = True
print("### started at line {}".format(lineNo))
break
if started:
collected_lines.append(line)
print("collected_lines: \n\n", *[ item for item in collected_lines ])
gives:
step 1
### started at line 2
### end at line 7
collected_lines:
PLAY NO. 1
1. adknjkd
2. skdi
3. ljdij
NOTES about fixed issues:
used .lstrip() in order to make .startswith() working as expected
added a space between NO. and {} in startswith('PLAY NO. {}'.format(n) so that the if condition can find the line
rearranged the order of ifs in order to avoid that the end line is considered found at the start line
added started = False to the loop to stop collecting the lines.
The problem with the leading spaces was already enough to prevent the code from finding the line. Fixing this alone wouldn't fix the problem because of the missing space in the format string, so both issues had to be fixed to make the code work as expected. And so on ... see NOTES above.
If you want a dict with as labels the play number and as items a list with the lines about the play you can use a defaultdict
Defining the text
text = """Hello and Welcome This is the list of plays being performed here
PLAY NO. 1
1. adknjkd
2. skdi
3. ljdij
PLAY NO. 2
1. hsnfhkjdnckj
2. sjndkjhnd and so on"""
Defining the regular expression
regex = re.compile('^\s*PLAY NO. (\d+)$')
Parsing the lines
label = None # no play to start with
recorded_lines = defaultdict(list)
for line_no, line in enumerate(StringIO(text)):
# In the real code replace the 'StringIO(text)' with 'file'
try:
play_no = int(regex.findall(line)[0])
# If this regex does not match, it will throw an IndexError
# The code underneath is only executed when a new play starts
if label: # if there is no play underway, there can be no ending
print('PLAY NO. %i ended at line number %i' % (label, line_no-1))
label = play_no
print('PLAY NO. %i started at line number %i' % (play_no, line_no))
except IndexError:
# no new play started
if label and line.strip():
recorded_lines[play_no].append(line.strip())
print(line_no, line)
print(recorded_lines)
yields
defaultdict(list,
{1: [(2, '1. adknjkd'), (3, '2. skdi'), (4, '3. ljdij')],
2: [(7, '1. hsnfhkjdnckj'), (8, '2. sjndkjhnd and so on')]})
and this output on the stout:
0 Hello and Welcome This is the list of plays being performed here
PLAY NO. 1 started at line number 1
1 PLAY NO. 1
2 1. adknjkd
3 2. skdi
4 3. ljdij
5
PLAY NO. 1 ended at line number 5
PLAY NO. 2 started at line number 6
6 PLAY NO. 2
7 1. hsnfhkjdnckj
8 2. sjndkjhnd and so on
I have two dictionaries,
MaleDict = {'Jason':[(2014, 394),(2013, 350)...],
'Stephanie':[(2014, 3), (2013, 21),..]....}
FemaleDict = {'Jason':[(2014, 56),(2013, 23)...],
'Stephanie':[(2014, 335), (2013, 217),..]....}
I am attempting to add them so that
CompleteDict = {'Jason':[(2014, 394, 56),(2013, 350, 23)...],
'Stephanie':[(2014, 3, 335), (2013, 21, 217),..]....}
I have created a list comprehension that completes the task when the each dictionary has that year present. However, I need the output to present even if the year is not present in one of the MaleDict or FemaleDict. For example, if one year was not in the MaleDict the code would read ...'Stephanie':[....., (1999, 0, 389), ....]...
my list comprehensions are
for name_key in name_keys:
for year_key in year_keys:
[BaseDict[name_key].append((year_key, a[1], b[1])) for a in MaleDict[name_key] for b in FemaleDict[name_key] if (year_key == a[0] == b[0])]
#This is where I am stuck. My list comprehensions dont work when there is no value for a specific year
[BaseDict[name_key].append((year_key, a[1], 0)) for a in MaleDict[name_key] for b in FemaleDict[name_key] if (year_key == a[0] != b[0])]
[BaseDict[name_key].append((year_key, 0, b[1])) for a in MaleDict[name_key] for b in FemaleDict[name_key] if (year_key != a[0] == b[0])]
print(BaseDict)
If your data format is not set in stone, i would consider using a defaultdict from collections:
Instead of [(2014, 394),(2013, 350)...]
use collections.defaultdict(int, {2014: 394, 2013: 350}) etc.
Then you can use
for name_key in name_keys:
for year_key in year_keys:
CompleteDict[name_key].update([FemaleDict[year_key], MaleDict[year_key]])
CompleteDict['Stephanie'][1999] will then be [0, 389]
I am trying to create a program which tells me if a number's square has different digits.
I have an "Index Error" in the really long "if" line. How do I fix it?
a= 4486659
f= (a**2)
s= str(f)
for num in range (1089):
if s[6]==s[7] or s[6]==s[8] or s[6]==s[9] or s[6]==s[10] or s[6]==s[11] or s[6]==s[12] or s[6]==s[13] or s[6]==s[14] or s[6]==s[15] or s[7]==s[8] or s[7]==s[9] or s[7]==s[10] or s[7]==s[11] or s[7]==s[12] or s[7]==s[13] or s[7]==s[14] or s[7]==s[15] or s[8]==s[9] or s[8]==s[10] or s[8]==s[11] or s[8]==s[12] or s[8]==s[13] or s[8]==s[14] or s[9]==s[10] or s[9]==s[11] or s[9]==s[12] or s[9]==s[13] or s[9]==s[14] or s[9]==s[15] or s[10]==s[11] or s[10]==s[12] or s[10]==s[13] or s[10]==s[14] or s[10]==s[15] or s[11]==s[12] or s[11]==s[13] or s[11]==s[14] or s[11]==s[15] or s[12]==s[13] or s[12]==s[14] or s[12]==s[15] or s[13]==s[14] or s[13]==s[15] or s[14]==s[15]:
a= a+1
else:
print(a)
The index error is because your string s is only 14 chars long, but you try to access s[14] and s[15]
Since you cannot call a nonexistent item in a string, Try this:
if s[6]==s[7] or s[6]==s[8] or s[6]==s[9] or s[6]==s[10] or s[6]==s[11] or s[6]==s[12] or s[6]==s[13] or s[6]==s[14] or s[7]==s[8] or s[7]==s[9] or s[7]==s[10] or s[7]==s[11] or s[7]==s[12] or s[7]==s[13] or s[7]==s[14] or s[8]==s[9] or s[8]==s[10] or s[8]==s[11] or s[8]==s[12] or s[8]==s[13] or s[8]==s[14] or s[9]==s[10] or s[9]==s[11] or s[9]==s[12] or s[9]==s[13] or s[9]==s[14] or s[10]==s[11] or s[10]==s[12] or s[10]==s[13] or s[10]==s[14] or s[11]==s[12] or s[11]==s[13] or s[11]==s[14] or s[12]==s[13] or s[12]==s[14] or s[13]==s[14]: