Confused about Python code (Beginner) - python

I've come across a question that I was confused about so decided to look it up. However, I'm a bit confused as to what some of the functions do in the code. The question was 'write a function to get rid of duplicate letters'
def remove_duplicates(s):
result = ""
dic = {}
for i in s:
if i not in dic:
result+=i
if ord(i.lower()) >= ord('a') and ord(i.lower()) <= ord('z'):
dic[i] = 1
return result
print(remove_duplicates("bookkeeper"))
I'm a bit confused as to what the purpose of the result = "" and dic = {}? I've never seen this before so no idea how it works.
And what does result+=i mean? And finally I have absolutely no idea what's going in the if ord line. Ord is something I just learned an hour ago so I have no idea how it's interacting with i.lower and 'a' / 'z'.

result = "" creates a variable named result and initializes it to a blank string.
dic = {} creates a variable named dic and initializes it to an empty dictionary. (Dictionaries are special Python objects.)
result += i is shorthand for result = result + i.
The if ord line is ensuring that i is a letter between A and Z. (Although this seems a very roundabout way to do it.)
Perhaps you should spend some time with a basic Python tutorial?

result = "" and dic = {} initallize the variables result as an empty string ans dic as a dictionary.
result+=i mean === result = result + i
About the ord() it checks if i.lower is in "range" of a - z

Related

Why does [""] not behave as expected in recursion?

I am going through popular interview questions, and came up with the following solution to "Compute all permutations of a string."
def perm(s):
if len(s) == 0:
return ['']
else:
l = []
prev = perm(s[1:])
for old_str in prev:
for i in range(len(old_str)):
new_str = old_str[0:i] + s[0] + old_str[i:]
l.append(new_str)
return l
However, this solution returns [] on all input. If I make the string in the base case any string other than the empty string, the computation runs as expected. For example, with 'hi' in the base case, perm('abc') returns
['abchi', 'bachi', 'bcahi', 'bchai', 'acbhi', 'cabhi', 'cbahi', 'cbhai', 'achbi', 'cahbi', 'chabi', 'chbai', 'abhci', 'bahci', 'bhaci', 'bhcai', 'ahbci', 'habci', 'hbaci', 'hbcai', 'ahcbi', 'hacbi', 'hcabi', 'hcbai']
As far as I can tell the algorithm for this code is correct. I am unsure of why the empty string isn't behaving as I anticipate, while other strings do. I have referenced this thread for better solutions, but I am still puzzled by why this one doesn't work.
You should probably add a special case for len(s)==1.
As written, the recursion will go down to the base case with an empty string, and then prev will be []. The for loop that follows this will never run, because prev is empty, so the final result will be empty too.

Why do parenthesis make such a difference?

I wrote a code that returns the count of distinct case-insensitive alphabetic characters and numeric digits that occur more than once in the input string. Here's my code:
def duplicate_count(text):
sum_low = 0
dic_low = []
sum_up = 0
dic_up = []
sum_num = 0
dic_num = []
total = 0
for i in text:
if i.isalpha():
if i.islower() and text.count(i) > 1 and i not in dic_low:
dic_low.append(i)
sum_low = sum_low + 1
elif i.isupper() and text.count(i) > 1 and i not in dic_up:
dic_up.append(i)
sum_up = sum_up + 1
elif i.isdigit() and text.count(i) > 1 and i not in dic_num:
dic_num.append(i)
sum_num = sum_num + 1
total = sum_low + sum_up + sum_num
print (total)
The problem is, I noticed that when I missed parenthesis after "if i.isalpha()" this code worked perfectly with alphabetic characters but appeared to ignore digits, so for instance if I passed "aabbcdeBBAA" it printed "4", but if the argument was "11336" it printed "0". Later I found out that the parenthesis had been missed and corrected it, and the code started to work normally, but I still don't understand what the problem was. There was no any TraceBack, so I guess the problem was in missing parenthesis. Why does it make such a big difference?
PS: sorry if the code is too weird, I'm new to programming and just started to learn coding.
Thank you!
i.isalpha is an object (the method isalpha of your string i). It is not Null, nor does it correspond to a falsy value like 0, "", [] etc., so if checked for its boolean value, it is evaluated as True.
Only by adding (), you actually call that method.
A practical tip: There is a common beginners' mistake with file handles: myfile.close doesn't close the file myfile, only myfile.close() does. But the first statement is syntactically valid and will not raise an error. You just might be wondering why the file you just wrote is empty...
If you write i.isalpha means you are referring to the function, not actually calling the function, you need to add () at the end to call the function
>>> i = 'some text'
>>> obj = i.isalpha # just reference not actually call
>>> obj
<function str.isalpha>
>>> obj() # adding '()' executes the function
False
>>> i.isalpha()
False

Robber's language in python error

I am a beginning in Python.
I have a function that checks if it is a vowel.
def vowel(x):
if(x=='a' or x=='e' or x=='i' or x=='o' or x=='u'):
return True;
else:
return False;
And a function that tries to convert the string to a robber's language by using the vowel function above. (The algorithm for conversion is to double every consonant and place an "o" in between).
def robber(text):
s=""
for i,c in enumerate(text):
if vowel(c)==False:
s=s.join([c,'o',c])
return s;
When I try to run it by passing robber("asdf") into the function, I get a blank line and "Process finished with exit code 0"
I suspect that there might be multiple errors, but the program is syntactically correct. Could you help me with this?
You should append to s instead of assigning and also appending the c in case it is no vowel:
def robber(text):
s=""
for i,c in enumerate(text):
if vowel(c)==False:
s += ''.join([c,'o',c])
else:
s += c
return s
Furthermore some additional remarks:
it is more Pythonic to use not instead of == False;
you do not need to use enumerate(..) since i is never used;
you do not need to return True and return False if the test succeeds/fails, simply return the condition; and
you can rewrite both the vowel(..) and robber(..) function more elegantly.
So putting it together:
def vowel(x):
return x.lower() in ('a','e','i','o','u')
and:
def robber(text):
return ''.join([c if vowel(c) else ''.join((c,'o',c)) for c in text])
If you want to avoid all those append/overwrite errors (and get a much better performance/avoid string concatenation), better start writing those using list comprehension:
text = "asdf"
new_text = "".join([c if c in "aeiou" else "{0}o{0}".format(c) for c in text])
print(new_text)
result:
asosdodfof
the new text is a joined list (creates a string) of a list comprehension built using a ternary expression: leave the letter alone if vowel, else create the pattern.
Firstly, your problem
On the line s=s.join([c,'o',c]), you are actually replacing the contents of s every time. I think what you do want to do is to append it to s, so I would use s += "".join([c, 'o', c])
Also the use of join is wrong - the string before the join comes between every two elements in the given list, not before the first.
So, as I said, the correct form to do that should be:
s += "".join([c, 'o', c])
Disclaimer : Not tested.
Code readability
As you stated that you are a beginner, let me give you some tips about your coding style (Python's coding style is very unique).
1
Instead of doing x=='a' or x=='e' or x=='i' or x=='o' or x=='u', you do:
`if x in 'aeiou':`
Much more understandable and reads better.
2
Doing:
if ...:
return True
else
Return False
Is very clumsy. Try:
return ...
And in your case:
return x in 'aeiuo'
The condition is already a boolean value (True or False) - no need to reevaluate it ;)

Trying to learn how loops work, what is going wrong?

The question is :
Given a string, return a string where for every char in the original, there are two chars.
This is my attempt:
def double_char(str):
n = 0
for x in range(0, len(str)):
return 2*str[n]
n = n+1
When I run it, it only returns 2 versions of the first letter and doesn't loop properly. So for double_char(Hello) it just returns HH.
What is going wrong? Thanks in advance for any help, sorry for the really beginner question.
The return is causing your function to return in the first iteration so it just returns 2 of the first letter.
What you may have intended to write was something like
def double_char(s):
n = 0
r = ''
for x in range(0, len(s)):
r += 2*s[n]
n = n+1
return r
Building a string incrementally that is just 2 of each character.
A neater refactor of that function (without duplicating the other answer by using a comprehension) is
def double_char(s):
r = ''
for c in s:
r += 2*c
return r
You also should not use str as a variable name. It is a built in type and you are hiding that by defining a variable called str.
return returns control to the caller once reached, thus exiting your for loop prematurely.
Here's a simpler way to do that with str.join:
def double_char(s):
return ''.join(i*2 for i in s)
>>> s = 'Hello'
>>> double_char(s)
'HHeelllloo'
Do not use str as name to avoid shadowing the builtin str function.
Here is a different way to solving the question.
def double_char(str):
new_str = ""
for i in range(len(str)):
new_str += (str[i]*2)
return new_str
double_char('Hello')
'HHeelllloo'
def double_char(str):
string = ''
for i in range(len(str)):
string += str[i] * 2
i += 1
return string

'NoneType' object is not iterable - looping w/returned value

The purpose of this code is to find the longest string in alphabetical order that occurs first and return that subset.
I can execute the code once, but when I try to loop it I get 'NoneType' object is not iterable (points to last line). I have made sure that what I return and input are all not of NoneType, so I feel like I'm missing a fundamental.
This is my first project in the class, so the code doesn't need to be the "best" or most efficient way - it's just about learning the basics at this point.
s = 'efghiabcdefg'
best = ''
comp = ''
temp = ''
def prog(comp, temp, best, s):
for char in s:
if comp <= char: #Begins COMParison of first CHARacter to <null>
comp = char #If the following character is larger (alphabetical), stores that as the next value to compare to.
temp = temp + comp #Creates a TEMPorary string of characters in alpha order.
if len(temp) > len(best): #Accepts first string as longest string, then compares subsequent strings to the "best" length string, replacing if longer.
best = temp
if len(best) == len(s): #This is the code that was added...
return(s, best) #...to fix the problem.
else:
s = s.lstrip(temp) #Removes those characters considered in this pass
return (str(s), str(best)) #Provides new input for subsequent passes
while len(s) != 0:
(s, best) = prog(comp, temp, best, s)
prog is returning None. The error you get is when you try to unpack the result into the tuple (s, best)
You need to fix your logic so that prog is guaranteed to not return None. It will return None if your code never executes the else clause in the loop.
You don't return in all cases. In Python, if a function ends without an explicit return statement, it will return None.
Consider returning something if, for example, the input string is empty.

Categories