The problem that I have is printing phone_sorter() and number_calls() all on the same lines. For instance it will print the two lines of phone_sorter but the number_calls will be printed right below it. I have tried the end='' method but it does not seem to work.
customers=open('customers.txt','r')
calls=open('calls.txt.','r')
def main():
print("+--------------+------------------------------+---+---------+--------+")
print("| Phone number | Name | # |Duration | Due |")
print("+--------------+------------------------------+---+---------+--------+")
print(phone_sorter(), number_calls())
def time(x):
m, s = divmod(seconds, x)
h, m = divmod(m, x)
return "%d:%02d:%02d" % (h, m, s)
def phone_sorter():
sorted_no={}
for line in customers:
rows=line.split(";")
sorted_no[rows[1]]=rows[0]
for value in sorted(sorted_no.values()):
for key in sorted_no.keys():
if sorted_no[key] == value:
print(sorted_no[key],key)
def number_calls():
no_calls={}
for line in calls:
rows=line.split(";")
if rows[1] not in no_calls:
no_calls[rows[1]]=1
else:
no_calls[rows[1]]+=1
s={}
s=sorted(no_calls.keys())
for key in s:
print(no_calls[key])
main()
Your key problem is that both phone_sorter and number_calls do their own printing, and return None. So, printing their return values is absurd and should just end with a None None line that makes no sense, after they've done all their own separate-line printing.
A better approach is to restructure them to return, not print, the strings they determine, and only then arrange to print those strings with proper formatting in the "orchestrating" main function.
It looks like they'll each return a list of strings (which they are now printing on separate lines) and you'll likely want to zip those lists if they are in corresponding order, to prepare the printing.
But your code is somewhat opaque, so it's hard to tell if the orders of the two are indeed corresponding. They'd better be, if the final printing is to make sense...
Added: let me exemplify with some slight improvement and one big change in phone_sorter...:
def phone_sorter():
sorted_no={}
for line in customers:
rows=line.split(";")
sorted_no[rows[1]]=rows[0]
sorted_keys = sorted(sorted_no, key=sorted_no.get)
results = [(sorted_no[k], k) for k in sorted_keys]
return results
Got it? Apart from doing the computations better, the core idea is to put together a list and return it -- it's main's job to format and print it appropriately, in concert with a similar list returned by number_calls (which appears to be parallel).
def number_calls():
no_calls=collections.Counter(
line.split(';')[1] for line in calls)
return [no_calls(k) for k in sorted(no_calls)]
Now the relationship between the two lists is not obvious to me, but, assuming they're parallel, main can do e.g:
nc = no_calls()
ps = phone_sorter()
for (duration, name), numcalls in zip(ps, nc):
print(...however you want to format the fields here...)
Those headers you printed in main don't tell me what data should be printed under each, and how the printing should be formatted (width of
each field, for example). But, main, and only main, should be
intimately familiar with these presentation issues and control them, while the other functions deal with the "business logic" of extracting the data appropriately. "Separation of concerns" -- a big issue in programming!
Related
So guys, here is my code:
import io
import difflib
import re
with io.open('textest.txt', mode="r", encoding="utf_8_sig") as file:
lines1 = file.readlines()
with io.open('minitext.txt', mode="r", encoding="utf_8_sig") as file:
lines2 = file.readlines()
def prefilter(line):
return re.sub("\s+"," ",line.strip())
for d in difflib.ndiff([prefilter(x) for x in lines1],[prefilter(x) for x in lines2]):
print(d)
the textest.txt is the full song and the minitext.txt is just a part of it. The output is this (I know, it's a justin bieber song, it's just an example)
+ somethin' I don't wanna hold back
- For all the times that you rained on my parade
- And all the clubs you get in using my name
- You think you broke my heart, oh, girl, for goodness' sake
- You think I'm crying on my own, well, I ain't
- And I didn't wanna write a song
- 'Cause I didn't want anyone thinkin' I still care, I don't, but
- You still hit my phone up
- And baby, I'll be movin' on
- And I think you should be somethin' I don't wanna hold back
Maybe you should know that
My mama don't like you and she likes everyone
And I never like to admit that I was wrong
And I've been so caught up in my job
Didn't see what's going on, but now I know
+
+
+
I'm better sleeping on my own
+ 'Cause if you like the wa
- 'Cause if you like the way you look that much
- Oh, baby, you should go and love yourself
- And if you think that I'm still holdin' on to somethin'
The thing is: I wanted to print only the + (The different lines on the lines2, that is the minitext.txt), and the number of the line which is different. I also wanted to ignore the completely empty lines so the output is just like:
somethin' I don't wanna hold back (Number of line in minitext.txt)
'Cause if you like the wa (Number of line in minitext.txt)
or anything similiar. Is there a way I could do that?
if you go into difflib.py in your system (difflib.__file__ (get path for this module in your system))
you find that ndiff -> return Differ(linejunk, charjunk).compare(a, b)
after that inside Differ class check compare function....
this module work with _dump for yield (tag + string -->>> you see in print)
we overwrite this function for our own purpose
we filter tag(we need + tag)
filter string (we need not empty)
you can check(source code) and retrieve everything that you like.
import difflib
# over write Differ class (difflib.ndiff work with compare function that exist in this class)
class Differ(difflib.Differ):
# this function used for + tag
def _dump(self, tag, x, lo, hi):
"""Generate comparison results for a same-tagged range."""
for i in range(lo, hi):
# only yield if tag == "+"
if tag == '+':
# if second list not empty yield result
if x[i] != "":
# change format (item of second list string, i==index (number line start from 0))
yield '%s(%s)' % (x[i], i)
# example of two list of string
a = ["first", "second", "three", "four"]
b = ["number_one", "second", "number_three", "four"]
differ_object = Differ()
result = differ_object.compare(a, b)
for _ in result:
print(_)
# result
"""
number_one(0)
number_three(2)
"""
I am using python 2.7. I wrote a code to generate passwords. For doing this, I used the random module to generate how many characters of different types(uppercase, lowercase, special and numbers) to be used to generate a password of a given length. When a wrote a function for this, it was supposed to return a tuple, but it returns None. Why is it happening?
I tried the casual debugging method of putting print statements in between and figuring out where it went wrong. Everything works just fine, except it returns None.
def passlen(a):
"""Gives length of different characters to be put into passwords"""
uplen=random.randrange(0, a)
lwlen=random.randrange(0, a)
speclen=random.randrange(0, a)
nmbrlen=random.randrange(0, a)
if uplen+lwlen+speclen+nmbrlen==a:
print (uplen, lwlen, speclen, nmbrlen)
return(uplen, lwlen, speclen, nmbrlen)
else:
passlen(a)
x=input("how many characters in the password?")
print(passlen(x))
Expected results are 4-tuples, but it gives None instead.
So you want four random numbers that add to a? Of course you can try choosing four random numbers until you find a set that adds up to a, but that might take a while for large values of a (and you definitely don't want to do this recursively).
Much better to choose three split points between 0 and a:
def passlen(a):
splits = sorted([random.randrange(0,a) for _ in range(3)])
uplen = splits[0]
lwlen = splits[1] - uplen
speclen = splits[2] - uplen - lwlen
nmbrlen = a - uplen - lwlen - speclen
return uplen, lwlen, speclen, nmbrlen
Thanks to Kamiccolo for trying to help out.
The function should look like this:
def passlen(a):
"""Gives length of different characters to be put into passwords"""
uplen=int(random.randrange(0, a))
lwlen=int(random.randrange(0, a))
speclen=int(random.randrange(0, a))
nmbrlen=int(random.randrange(0, a))
bab=(uplen, lwlen, speclen, nmbrlen)
if uplen+lwlen+speclen+nmbrlen==a:
return bab
else:
return passlen(a)
A duplicate thread also helped me in this.
I have written an instance method which uses recursion to find a certain solution. It works perfectly fine except the time when I'm exiting the if-elif block. I call the function itself inside IF block. Also, I have only one return statement. The output from the method is weird for me to understand. Here is the code and the output:
def create_schedule(self):
"""
Creates the day scedule for the crew based on the crew_dict passed.
"""
sched_output = ScheduleOutput()
assigned_assignements = []
for i in self.crew_list:
assigned_assignements.extend(i.list_of_patients)
rest_of_items = []
for item in self.job.list_of_patients:
if item not in assigned_assignements:
rest_of_items.append(item)
print("Rest of the items are:", len(rest_of_items))
if len(rest_of_items) != 0:
assignment = sorted(rest_of_items, key=lambda x: x.window_open)[0]
# print("\nNext assignment to be taken ", assignment)
output = self.next_task_eligibility(assignment, self.crew_list)
if len(output) != 0:
output_sorted = sorted(output, key=itemgetter(2))
crew_to_assign = output_sorted[0][1]
assignment.eta = output_sorted[0][4]
assignment.etd = int(assignment.eta) + int(assignment.care_duration)
crew = next((x for x in self.crew_list if x.crew_number == crew_to_assign), None)
self.crew_list.remove(crew)
crew.list_of_patients.append(assignment)
crew.time_spent = assignment.etd
self.crew_list.append(crew)
self.create_schedule()
else:
print("*" * 80, "\n", "*" * 80, "\nWe were not able to assign a task so stopped.\n", "*" * 80, "\n", "*" * 80)
sched_output.crew_output = self.crew_list
sched_output.patients_left = len(rest_of_items)
elif not rest_of_items:
print("Fully solved.")
sched_output.crew_output = self.crew_list
sched_output.patients_left = 0
print("After completely solving coming here.")
return sched_output
This was the output:
Rest of the items are: 10
Rest of the items are: 9
Rest of the items are: 8
Rest of the items are: 7
Rest of the items are: 6
Rest of the items are: 5
Rest of the items are: 4
Rest of the items are: 3
Rest of the items are: 2
Rest of the items are: 1
Rest of the items are: 0
Fully solved.
After completely solving coming here.
After completely solving coming here.
After completely solving coming here.
After completely solving coming here.
After completely solving coming here.
After completely solving coming here.
After completely solving coming here.
After completely solving coming here.
After completely solving coming here.
After completely solving coming here.
After completely solving coming here.
What I don't understand is that as soon as my list rest_of_items is empty, I assign data to sched_output and return it. However, print statement is being executed for the same number of time as recursion was done. How can I avoid this?
My output is perfectly fine. All I want to do is understand the cause of this behaviour and how to avoid it.
The reason it's printing out 11 times is that you always call print at the end of the function, and you're calling the function 11 times. (It's really the same reason you get Rest of the items are: … 11 times, which should be a lot more obvious.)
Often, the best solution is to redesign things so instead of doing "side effects" like print inside the function, you just return a value, and the caller can then do whatever side effects it wants with the result. In that case, it doesn't matter that you're calling print 11 times; the print will only happen once, in the caller.
If that isn't possible, you can change this so that you only print something when you're at the top of the stack. But in many recursive functions, there's no obvious way to figure that out without passing down more information:
def create_schedule(self, depth=0):
# etc.
self.create_schedule(depth+1)
# etc.
if not depth:
print('After completely solving come here.')
returns sched_output
The last resort is to just wrap the recursive function, like this:
def _create_schedule(self):
# etc.
self._create_schedule()
# etc.
# don't call print
return sched_output
def create_schedule(self):
result = self._create_schedule()
print('After completely solving come here.')
return result
That's usually only necessary when you need to do some one-time setup for the recursive process, but here you want to do some one-time post-processing instead, which is basically the same problem, so it can be solved the same way.
(Of course this is really just the first solution in disguise, but it's hidden inside the implementation of create_schedule, so you don't need to change the interface that the callers see.)
As you call your create_schedule function within itself before the function finishes, once it has gotten to the end and doesn't need to call itself again, each function ends, and hits the "After completely solving coming here.", at the end of the function.
This means that each function, after calling itself, is still running - just stuck at the line where it calls itself - until they have all completed, which is when the paused functions can finish their task, printing out your statement.
You have print("After completely solving coming here.") at the end of your recursive function. That line will be executed once for each recursion.
Consider this simple example, which recreates your issue:
def foo(x):
print("x = {x}".format(x=x))
if x > 1:
foo(x-1)
print("Done.")
Now call the function:
>>> foo(5)
x = 5
x = 4
x = 3
x = 2
x = 1
Done.
Done.
Done.
Done.
Done.
As you can see, on the final call to foo(x=0), it will print "Done.". At that point, the function will return to the previous call, which will also print "Done." and so on.
I've been learning Python for a couple of months, and wanted to understand a cleaner and more efficient way of writing this function. It's just a basic thing I use to look up bus times near me, then display the contents of mtodisplay on an LCD, but I'm not sure about the mtodisplay=mtodisplay+... line. There must be a better, smarter, more Pythonic way of concatenating a string, without resorting to lists (I want to output this string direct to LCD. Saves me time. Maybe that's my problem ... I'm taking shortcuts).
Similarly, my method of using countit and thebuslen seems a bit ridiculous! I'd really welcome some advice or pointers in making this better. Just wanna learn!
Thanks
json_string = requests.get(busurl)
the_data = json_string.json()
mtodisplay='220 buses:\n'
countit=0
for entry in the_data['departures']:
for thebuses in the_data['departures'][entry]:
if thebuses['line'] == '220':
thebuslen=len(the_data['departures'][entry])
print 'buslen',thebuslen
countit += 1
mtodisplay=mtodisplay+thebuses['expected_departure_time']
if countit != thebuslen:
mtodisplay=mtodisplay+','
return mtodisplay
Concatenating strings like this
mtodisplay = mtodisplay + thebuses['expected_departure_time']
Used to be very inefficient, but for a long time now, Python does reuse the string being catentated to (as long as there are no other references to it), so it's linear performance instead of the older quadratic performance which should definitely be avoided.
In this case it looks like you already have a list of items that you want to put commas between, so
','.join(some_list)
is probably more appropriate (and automatically means you don't get an extra comma at the end).
So next problem is to construct the list(could also be a generator etc.). #bgporter shows how to make the list, so I'll show the generator version
def mtodisplay(busurl):
json_string = requests.get(busurl)
the_data = json_string.json()
for entry in the_data['departures']:
for thebuses in the_data['departures'][entry]:
if thebuses['line'] == '220':
thebuslen=len(the_data['departures'][entry])
print 'buslen',thebuslen
yield thebuses['expected_departure_time']
# This is where you would normally just call the function
result = '220 buses:\n' + ','.join(mtodisplay(busurl))
I'm not sure what you mean by 'resorting to lists', but something like this:
json_string = requests.get(busurl)
the_data = json_string.json()
mtodisplay= []
for entry in the_data['departures']:
for thebuses in the_data['departures'][entry]:
if thebuses['line'] == '220':
thebuslen=len(the_data['departures'][entry])
print 'buslen',thebuslen
mtodisplay.append(thebuses['expected_departure_time'])
return '220 buses:\n' + ", ".join(mtodisplay)
I'm creating objects derived from a rather large txt file. My code is working properly but takes a long time to run. This is because the elements I'm looking for in the first place are not ordered and not (necessarily) unique. For example I am looking for a digit-code that might be used twice in the file but could be in the first and the last row. My idea was to check how often a certain code is used...
counter=collections.Counter([l[3] for l in self.body])
...and then loop through the counter. Advance: if a code is only used once you don't have to iterate over the whole file. However You are stuck with a lot of iterations which makes the process really slow.
So my question really is: how can I improve my code? Another idea of course is to oder the data first. But that could take quite long as well.
The crucial part is this method:
def get_pc(self):
counter=collections.Counter([l[3] for l in self.body])
# This returns something like this {'187':'2', '199':'1',...}
pcode = []
#loop through entries of counter
for k,v in counter.iteritems():
i = 0
#find post code in body
for l in self.body:
if i == v:
break
# find fist appearence of key
if l[3] == k:
#first encounter...
if i == 0:
#...so create object
self.pc = CodeCana(k,l[2])
pcode.append(self.pc)
i += 1
# make attributes
self.pc.attr((l[0],l[1]),l[4])
if v <= 1:
break
return pcode
I hope the code explains the problem sufficiently. If not, let me know and I will expand the provided information.
You are looping over body way too many times. Collapse this into one loop, and track the CodeCana items in a dictionary instead:
def get_pc(self):
pcs = dict()
pcode = []
for l in self.body:
pc = pcs.get(l[3])
if pc is None:
pc = pcs[l[3]] = CodeCana(l[3], l[2])
pcode.append(pc)
pc.attr((l[0],l[1]),l[4])
return pcode
Counting all items first then trying to limit looping over body by that many times while still looping over all the different types of items defeats the purpose somewhat...
You may want to consider giving the various indices in l names. You can use tuple unpacking:
for foo, bar, baz, egg, ham in self.body:
pc = pcs.get(egg)
if pc is None:
pc = pcs[egg] = CodeCana(egg, baz)
pcode.append(pc)
pc.attr((foo, bar), ham)
but building body out of a namedtuple-based class would help in code documentation and debugging even more.