Issue with pretty tables in python - python

I'm currently working on a assignment for school, Im not asking for anyone to solve the problem for me, Im just trying to figure out what it is im doing wrong with pretty tables. Here is the code I have for the table itself
import random
from prettytable import PrettyTable
x = PrettyTable
def generate_bingo_card():
dict = {'B': [], 'I': [], 'N': [], 'G': [], 'O': []}
counter = 0
while True:
if counter == 5:
break
else:
randb = random.randint(1, 15)
randi = random.randint(16, 30)
randn = random.randint(31, 45)
randg = random.randint(46, 60)
rando = random.randint(61, 75)
dict['B'].append(randb)
dict['I'].append(randi)
dict['N'].append(randn)
dict['G'].append(randg)
dict['O'].append(rando)
counter += 1
return dict
def print_bingo_card(card):
x.add_column('B', [card['B']])
x.add_column('I', [card['I']])
x.add_column('N', [card['N']])
x.add_column('G', [card['G']])
x.add_column('O', [card['O']])
print(print_bingo_card(generate_bingo_card()))
and here is the error im getting
File "C:\Users\Joshu\OneDrive\Desktop\Python assignment 3\a3q6_bingo.py", line 26, in print_bingo_card
x.add_column('B', [card['B']])
TypeError: PrettyTable.add_column() missing 1 required positional argument: 'column'
I've followed the documentation to a tee and am still getting this error, If someone could point me in the right direction that would be great!

I think this is a much more elegant solution; you have added complexity that I don't feel needs to exist; you can always retrofit this to your solution;
import prettytable
import random
def create_bingo_card():
card = {}
card['B'] = random.sample(range(1, 16), 5)
card['I'] = random.sample(range(16, 31), 5)
card['N'] = random.sample(range(31, 46), 5)
card['G'] = random.sample(range(46, 61), 5)
card['O'] = random.sample(range(61, 76), 5)
card['N'] = random.sample(range(76, 95), 5)
# create a pretty table
pt = prettytable.PrettyTable(field_names=['B', 'I', 'N', 'G', 'O'])
for row in zip(*[card['B'], card['I'], card['N'], card['G'], card['O']]):
pt.add_row(row)
return pt
card = create_bingo_card()
print(card)
Output:
+----+----+----+----+----+
| B | I | N | G | O |
+----+----+----+----+----+
| 1 | 17 | 37 | 54 | 74 |
| 5 | 21 | 33 | 57 | 64 |
| 6 | 24 | 78 | 60 | 71 |
| 10 | 19 | 44 | 47 | 69 |
| 2 | 30 | 41 | 52 | 62 |
+----+----+----+----+----+

Related

How should I solve logic error in timestamp using Python?

I have written a code to calculate a, b, and c. They were initialized at 0.
This is my input file
-------------------------------------------------------------
| Line | Time | Command | Data |
-------------------------------------------------------------
| 1 | 0015 | ACTIVE | |
| 2 | 0030 | WRITING | |
| 3 | 0100 | WRITING_A | |
| 4 | 0115 | PRECHARGE | |
| 5 | 0120 | REFRESH | |
| 6 | 0150 | ACTIVE | |
| 7 | 0200 | WRITING | |
| 8 | 0314 | PRECHARGE | |
| 9 | 0318 | ACTIVE | |
| 10 | 0345 | WRITING_A | |
| 11 | 0430 | WRITING_A | |
| 12 | 0447 | WRITING | |
| 13 | 0503 | WRITING | |
and the timestamps and commands are used to process the calculation for a, b, and c.
import re
count = {}
timestamps = {}
with open ("page_stats.txt", "r") as f:
for line in f:
m = re.split(r"\s*\|\s*", line)
if len(m) > 3 and re.match(r"\d+", m[1]):
count[m[3]] = count[m[3]] + 1 if m[3] in count else 1
#print(m[2])
if m[3] in timestamps:
timestamps[m[3]].append(m[2])
#print(m[3], m[2])
else:
timestamps[m[3]] = [m[2]]
#print(m[3], m[2])
a = b = c = 0
for key in count:
print("%-10s: %2d, %s" % (key, count[key], timestamps[key]))
if timestamps["ACTIVE"] > timestamps["PRECHARGE"]: #line causing logic error
a = a + 1
print(a)
Before getting into the calculation, I assign the timestamps with respect to the commands. This is the output for this section.
ACTIVE : 3, ['0015', '0150', '0318']
WRITING : 4, ['0030', '0200', '0447', '0503']
WRITING_A : 3, ['0100', '0345', '0430']
PRECHARGE : 2, ['0115', '0314']
REFRESH : 1, ['0120']
To get a, the timestamps of ACTIVE must be greater than PRECHARGE and WRITING must be greater than ACTIVE. (Line 4, 6, 7 will contribute to the first a and Line 8, 9, and 12 contributes to the second a)
To get b, the timestamps of WRITING must be greater than ACTIVE. For the lines that contribute to a such as Line 4, 6, 7, 8, 9, and 12, they cannot be used to calculate b. So, Line 1 and 2 contribute to b.
To get c, the rest of the unused lines containing WRITING will contribute to c.
The expected output:
a = 2
b = 1
c = 1
However, in my code, when I print a, it displays 0, which shows the logic has some error. Any suggestion to amend my code to achieve the goal? I have tried for a few days and the problem is not solved yet.
I made a function that will return the commands in order that match a pattern with gaps allowed.
I also made a more compact version of your file reading.
There is probably a better version to divide the list into two parts, the problem was to only allow elements in that match the whole pattern. In this one I iterate over the elements twice.
import re
commands = list()
with open ("page_stats.txt", "r") as f:
for line in f:
m = re.split(r"\s*\|\s*", line)
if len(m) > 3 and re.match(r"\d+", m[1]):
_, line, time, command, data, _ = m
commands.append((line,time,command))
def search_pattern(pattern, iterable, key=None):
iter = 0
count = 0
length = len(pattern)
results = []
sentinel = object()
for elem in iterable:
original_elem = elem
if key is not None:
elem = key(elem)
if elem == pattern[iter]:
iter += 1
results.append((original_elem,sentinel))
if iter >= length:
iter = iter % length
count += length
else:
results.append((sentinel,original_elem))
matching = []
nonmatching = []
for res in results:
first,second = res
if count > 0:
if second is sentinel:
matching.append(first)
count -= 1
elif first is sentinel:
nonmatching.append(second)
else:
value = first if second is sentinel else second
nonmatching.append(value)
return matching, nonmatching
pattern_a = ['PRECHARGE','ACTIVE','WRITING']
pattern_b = ['ACTIVE','WRITING']
pattern_c = ['WRITING']
matching, nonmatching = search_pattern(pattern_a, commands, key=lambda t: t[2])
a = len(matching)//len(pattern_a)
matching, nonmatching = search_pattern(pattern_b, nonmatching, key=lambda t: t[2])
b = len(matching)//len(pattern_b)
matching, nonmatching = search_pattern(pattern_c, nonmatching, key=lambda t: t[2])
c = len(matching)//len(pattern_c)
print(f'{a=}')
print(f'{b=}')
print(f'{c=}')
Output:
a=2
b=1
c=1

Bingo card generating duplicate numbers

I created a simple Bingo card generator that generates 4 numbers between n and n+15. However, I noticed that numbers are sometimes generated twice despite an if statement I wrote that was supposed to find duplicates and rerun the random generation for that cell. My code is below:
import random
ballCount = 75 # Max value of cell
gridWidth = 4
gridHeight = 5
numPerCard = 20 # Numbers generated per card
minimum = 1
maximum = 15
def generate_number(stored, small_num, big_num):
random.seed(a=None, version=2)
random_number = str(random.randint(small_num, big_num))
if "| "+random_number+" |" in stored:
generate_number(stored, small_num, big_num)
return random_number
for row in range(gridHeight):
string = ""
for Number in range(gridWidth):
number = generate_number(string, minimum, maximum)
string += " | " + number
string += " |"
print(string)
maximum += 15
minimum += 15
And here is an example of output with duplicates (23 appears 2 times):
| 2 | 5 | 9 | 12 |
| 25 | 23 | 19 | 23 |
| 37 | 42 | 30 | 37 |
| 60 | 49 | 50 | 55 |
| 73 | 71 | 69 | 67 |
if "| "+random_number+" |" in stored:
generate_number(stored, small_num, big_num)
return random_number
If you already have the number, you call generate_number again, but you still return the original number (the duplicate).
You may be interested in random.sample as an alternative way of getting a random selection of unique numbers within a range. E.g.:
>>> [random.sample(range(n, n+15), 4) for n in range(15, 75, 15)]
[[20, 26, 15, 23], [37, 44, 32, 40], [48, 45, 47, 50], [63, 62, 68, 71]]
or, with pretty-printing:
>>> for row in [random.sample(range(n, n+15), 4) for n in range(15, 75, 15)]:
... print(f"| {' | '.join(map(str, row))} |")
...
| 17 | 15 | 27 | 22 |
| 34 | 33 | 42 | 36 |
| 54 | 51 | 55 | 48 |
| 68 | 73 | 61 | 72 |
Inside the if statement you need to return the result from generate_number. Right now it will do the if statement and then discard that result and then return the original number.
Problems found in your code:
1) Your 'stored' variable in generate_number is missing the vertical bar "|" in the end, so number doesn't match.
2) The return of your recursive function must be assigned to "random_number".
Follow the corrected code:
import random
ballCount = 75 # Max value of cell
gridWidth = 4
gridHeight = 5
numPerCard = 20 # Numbers generated per card
cards = 6 # Number of cards
minimum = 1
maximum = 15
def generate_number(stored, small_num, big_num):
random.seed(a=None, version=2)
random_number = str(random.randint(small_num, big_num))
if "| " + random_number + " |" in stored +" |":
random_number = generate_number(stored, small_num, big_num)
return random_number
for row in range(gridHeight):
string = ""
for Number in range(gridWidth):
number = generate_number(string, minimum, maximum)
string += " | " + number
string += " |"
print(string)
maximum += 15
minimum += 15
Hope this helps
There are two problems I can see here. The first problem is, when your program retries the random number generation, it doesn't do anything with the result. You should add a return before generate_number(stored, small_num, big_num), making it return generate_number(stored, small_num, big_num). Secondly, you should remove the " |" in the "| "+random_number+" |". It can be possible that the repetition is at the last cell you generated, and therefore does not have a " |" after it. Hope this answers your question.

Compare the columns in the database with the variables obtained in the python code

I have a MySQL database using Python(mysql.connector). This is my table:
+----+-------+-------+--------+------------+
| id | num1 | num2 | gen | filename |
+----+-------+-------+--------+------------+
| 1 | 45 | 55 | woman | vid1.mp4 |
| 2 | 25 | 35 | man | vid2.mp4 |
| 3 | 45 | 55 | man | vid3.mp4 |
| 4 | 5 | 15 | woman | vid4.mp4 |
I then get the list below by querying the database:
[(1, 45, 55, 'woman', 'vid1.mp4'), (2, 25, 35, 'man', 'vid2.mp4'),(3, 45, 55, 'man', 'vid3.mp4'),(4, 5, 15, 'woman', 'vid4.mp4')]
I get the number and gender in my code and compare it with the num1, num2 and gender entered in the database.
For example:
if 25<num<35 and gender =='man':
filename = 'vid2.mp4'
How could I implement this?
When I have a list of data like you have specified here, it is useful to add column names to it.
data = [(1, 45, 55, 'woman', 'vid1.mp4') ... ] # This comes from DB
col_names = ['id','num1','num2','gen','filename']
Next, iterate over your data in a loop
for row in data:
# row now contains a single value, for instance (1, 45, 55, 'woman', 'vid1.mp4')
row_dict = dict(zip(col_names, row))
# row_dict is now a dictionary of {'id':1, 'num1':45 ... }
if row_dict['num1'] == 25:
print("%s has an num1 of 25!" % row_dict)
I hope that this gives you an idea how to iterate over your data and detect certain values are as you expect.
Another options is to use tuple unpacking in the loop
for id, num1, num2, gen, filename in data:
if num1 == 25:
print ("wow!")
Based on your edit:
for id, num1, num2, gen, db_filename in data:
if 25<num1<35 and gen == 'man':
filename = db_filename
else:
print("Oh no, file not found")
filename = None

Summarize data in a list in python

In python i need to summarize data in count_list this way (like a histogram):
"""
number | occurence
0 | *
1 | **
2 | ***
3 | **
4 | **
5 | *
6 | *
7 | **
8 | ***
9 | *
10 | **
"""
But instead I get this wrong output:
"""
number | occurence
0 |
1 | **
2 |
3 |
4 |
5 |
6 | **
7 |
8 |
9 |
10 | **
"""
Here is my code:
import random
random_list = []
list_length = 20
while len(random_list) < list_length:
random_list.append(random.randint(0,10))
count_list = [0] * 11
index = 0
while index < len(random_list):
number = random_list[index]
count_list[number] = count_list[number] + 1
index = index + 1
def summerizer():
index = 0
print count_list
print '"'*3
print 'number | occurrence'
while index < len(count_list):
print '%s' %' '*(7),
print index,#the problem is here
print ' | ',#and here
print '%s' %'*'*(count_list[index])
index += 1
print '%s'%'"'*3
summerizer()
This method uses collections.Counter:
from collections import Counter
import random
random_list = []
list_length = 20
while len(random_list) < list_length:
random_list.append(random.randint(0,10))
c = Counter(random_list)
print('number | occurrence')
def summerizer(dic):
for v,d in dic.items():
print(v, '|', '%s'%'*'*c[v])
summerizer(dic)
Yes i have found the problem
It is from the ide itself !!!
This was a quiz in a course on UDACITY android application and the embedded compiler inside it make this wrong answer..
Same code i tried now from pydroid application on Android also made the answer that i need without any change
Thanks for trying to help all of you
`import random
random_list = []
list_length = 20
while len(random_list) < list_length:
random_list.append(random.randint(0,10))
count_list = [0] * 11
index = 0
while index < len(random_list):
number = random_list[index]
count_list[number] = count_list[number] + 1
index = index + 1
def summerizer():
index = 0
print count_list
print '"'*3
print 'number | occurrence'
while index < len(count_list):
print '%s' %' '*(7),
print index,
print ' | ',
print '%s' %'*'*(count_list[index])
index += 1
print '%s'%'"'*3
summerizer()`
Try this
import random
random_list = []
list_length = 20
while len(random_list) < list_length:
random_list.append(random.randint(0,10))
dic={}
for i in random_list:
dic[i]=dic.get(i,0)+1
print 'number | occurrence'
for i in range(0,11):
if(i not in dic):
print i,"|",'%s' %'*'*(0)
else:
print i,"|",'%s' %'*'*(dic[i])
Out put
[9, 8, 4, 2, 5, 4, 8, 3, 5, 6, 9, 5, 3, 8, 6, 2, 10, 10, 8, 9]
number | occurrence
0 |
1 |
2 | **
3 | **
4 | **
5 | ***
6 | **
7 |
8 | ****
9 | ***
10 | **

How do I put data from a while loop into a table?

Basically I'm estimating pi using polygons. I have a loop which gives me a value for n, ann and bnn before running the loop again. here is what I have so far:
def printPiTable(an,bn,n,k):
"""Prints out a table for values n,2n,...,(2^k)n"""
u = (2**k)*n
power = 0
t = ((2**power)*n)
while t<=u:
if power < 1:
print(t,an,bn)
power = power + 1
t = ((2**power)*n)
else:
afrac = (1/2)*((1/an)+(1/bn))
ann = 1/afrac
bnn = sqrt(ann*bn)
print(t,ann,bnn)
an = ann
bn = bnn
power = power + 1
t = ((2**power)*n)
return
This is what I get if I run it with these values:
>>> printPiTable(4,2*sqrt(2),4,5)
4 4 2.8284271247461903
8 3.3137084989847607 3.0614674589207187
16 3.1825978780745285 3.121445152258053
32 3.1517249074292564 3.1365484905459398
64 3.1441183852459047 3.1403311569547534
128 3.1422236299424577 3.1412772509327733
I want to find a way to make it instead of printing out these values, just print the values in a nice neat table, any help?
Use string formatting. For example,
print('{:<4}{:>20f}{:>20f}'.format(t,ann,bnn))
produces
4 4.000000 2.828427
8 3.313708 3.061467
16 3.182598 3.121445
32 3.151725 3.136548
64 3.144118 3.140331
128 3.142224 3.141277
{:<4} is replaced by t, left-justified, formatted to a string of length 4.
{:>20f} is replaced by ann, right-justified, formatted as a float to a string of length 20.
The full story on the format string syntax is explained here.
To add column headers, just add a print statement like
print('{:<4}{:>20}{:>20}'.format('t','a','b'))
For fancier ascii tables, consider using a package like prettytable:
import prettytable
def printPiTable(an,bn,n,k):
"""Prints out a table for values n,2n,...,(2^k)n"""
table = prettytable.PrettyTable(['t', 'a', 'b'])
u = (2**k)*n
power = 0
t = ((2**power)*n)
while t<=u:
if power < 1:
table.add_row((t,an,bn))
power = power + 1
t = ((2**power)*n)
else:
afrac = (1/2)*((1/an)+(1/bn))
ann = 1/afrac
bnn = sqrt(ann*bn)
table.add_row((t,ann,bnn))
an = ann
bn = bnn
power = power + 1
t = ((2**power)*n)
print(table)
printPiTable(4,2*sqrt(2),4,5)
yields
+-----+---------------+---------------+
| t | a | b |
+-----+---------------+---------------+
| 4 | 4 | 2.82842712475 |
| 8 | 3.31370849898 | 3.06146745892 |
| 16 | 3.18259787807 | 3.12144515226 |
| 32 | 3.15172490743 | 3.13654849055 |
| 64 | 3.14411838525 | 3.14033115695 |
| 128 | 3.14222362994 | 3.14127725093 |
+-----+---------------+---------------+
Perhaps it is overkill for this sole purpose, but Pandas can make nice tables too, and can export them in other formats, such as HTML.
You can use output formatting to make it look pretty. Look here for an example:
http://docs.python.org/release/1.4/tut/node45.html

Categories