I'm very new to python and am having trouble with the following bit of code. The aim is to create a function that prints all the integers within a string.
def get_digits(str1):
for i in str1:
if i.isdigit():
return i
However it is only returning the first integer in the string, and I am unsure on how to get it to print all of them.
My apologies if the question is stupid, I have looked around for a while on this site and others and haven't been able to work it out.
Condensed down into a list comprehension
def get_digits(strval):
return [i for i in strval if i.isdigit()]
print get_digits('432jfsd5fs')
print ''.join(get_digits('432jfsd5fs'))
Returns
['4', '3', '2', '5']
4325
Whenever you return from a function, the function stops executing. I would recommend a generator here, which allows you to return an iterable from a function without writing much code.
This question smacks of homework, so I'm not going to give the full answer, but I would recommend looking at this StackOverflow answer for a great explanation of generators and the yield keyword.
>>> def print_digits(str1):
... for i in str1:
... if i.isdigit():
... print i
...
>>> print_digits("a12b3")
1
2
3
print prints things. return sends the answer back to whatever ran the function. i guess you are confusing the two because if you run a function within python it prints whatever is returned. but that is only because python is trying to be helpful and show you the result; it's not how you normally print things.
if you really want return the digits, and print them elsewhere, then one way to do it is build a list of results:
>>> def get_digits(str1):
... results = []
... for i in str1:
... if i.isdigit():
... results.append(i)
... return results
...
>>> print(get_digits("a12b3"))
['1', '2', '3']
Your function quits after it finds the first digit. In order for it to return all the digits, collect the results in a list.
def get_digits(str1):
digits = []
for i in str1:
if i.isdigit():
digits.append(i)
return digits
You can also simplify your function, by using a list comprehension:
def get_digits(str1):
return [d for d in str1 if d.isdigit()]
If you just want to print the results and not return them, replace return i with print i in your original function.
You can loop through the digits and return a list of them, like this:
def get_digits(str1):
digits = [] # define new list
for i in str1:
if i.isdigit():
digitis.append(i) # i is a digit, append to list
return digits # return the list of digits
def get_digits(str1):
numbers = ""
for i in str1:
if i.isdigit():
numbers = numbers + i
return numbers
Simple explanation:
# your code
def get_digits(str1):
for i in str1:
if i.isdigit():
return i
when a function meets return i, it stops its further execution, and return the value.
Since others has explained in detail, I'll just put more solutions for reference:
#1. Using generator
def get_digits_generator(str1):
for i in str1:
if i.isdigit():
yield i
#2. Returning a list of digits
def get_digits_list(str1):
list_of_digits = []
for i in str1:
if i.isdigit():
list_of_digits.append(i)
return list_of_digits
#3. List comprehension
str1 = "asdbh12njasdo29ns"
list_of_digits = [character for character in str1 if character.isdigit()]
import re
re.findall('\d', str1)
a=""
def get_digits(str1):
for i in str1:
if i.isdigit():
a=a&i
return a
try it like this. Because you return while you find the first digital.
Related
I'm trying to write a function to return the longest common prefix from a series of strings. Using a debugger, saw that my function reaches the longest common prefix correctly, but then when it reaches the statement to return, it begins reverting to earlier stages of the algorithm.
For test case strs = ["flower","flow","flight"]
The output variable holds the following values:-
f > fl > f
instead of returning fl.
Any help would be appreciated, because I don't really know how to Google for this one. Thank you.
class Solution(object):
def longestCommonPrefix(self, strs, output = ''):
#return true if all chars in string are the same
def same(s):
return s == len(s) * s[0]
#return new list of strings with first char removed from each string
def slicer(list_, list_2 = []):
for string in list_:
string1 = string[1:]
list_2.append(string1)
return list_2
#return string containing first char from each string
def puller(list_):
s = ''
for string in list_:
s += string[0]
return s
#pull first character from each string
s = puller(strs)
#if they are the same
#add one char to output
#run again on sliced list
if same(s):
output += s[0]
self.longestCommonPrefix(slicer(strs), output)
return output
This can be handled with os.path.commonprefix.
>>> import os
>>> strs = ["flower","flow","flight"]
>>> os.path.commonprefix(strs)
'fl'
It doesn't "revert". longestCommonPrefix potentially calls itself - what you're seeing is simply the call-stack unwinding, and flow of execution is returning to the calling code (the line that invoked the call to longestCommonPrefix from which you are returning).
That being said, there's really no need to implement a recursive solution in the first place. I would suggest something like:
def get_common_prefix(strings):
def get_next_prefix_char():
for chars in zip(*strings):
if len(set(chars)) != 1:
break
yield chars[0]
return "".join(get_next_prefix_char())
print(get_common_prefix(["hello", "hey"]))
You are looking at the behavior...the final result...of recursive calls to your method. However, the recursive calls don't do anything to affect the result of the initial execution of the method. If we look at the few lines that matter at the end of your method:
if same(s):
output += s[0]
self.longestCommonPrefix(slicer(strs), output)
return output
The problem here is that since output is immutable, its value won't be changed by calling longestCommonPrefix recursively. So from the standpoint of the outermost call to longestCommonPrefix, the result it will return is determined only by if same(s) is true or false. If it is true it will return s[0], otherwise it will return ''.
The easiest way to fix this behavior and have your recursive call affect the result of the prior call to the method would be to have its return value become the value of output, like this:
if same(s):
output += s[0]
output = self.longestCommonPrefix(slicer(strs), output)
return output
This is a common code pattern when using recursion. Just this change does seem to give you the result you expect! I haven't analyzed your whole algorithm, so I don't know if it becomes "correct" with just this change.
Can you try this? I
class Solution(object):
def longestCommonPrefix(self, strs, output = ''):
#return true if all chars in string are the same
def same(s):
return s == len(s) * s[0]
#return new list of strings with first char removed from each string
def slicer(list_, list_2 = []):
for string in list_:
string1 = string[1:]
list_2.append(string1)
return list_2
#return string containing first char from each string
def puller(list_):
s = ''
for string in list_:
s += string[0]
return s
#pull first character from each string
s = puller(strs)
# Can you Try this revision?
# I think the problem is that your new version of output is being lost when the fourth called function returns to the third and the third returns to the second, etc...
# You need to calculate a new output value before you call recursively, that is true, but you also need a way to 'store' that output when that recursively called function 'returns'. Right now it disappears, I believe.
if same(s):
output += s[0]
output = self.longestCommonPrefix(slicer(strs), output)
return output
I'm an amateur learner and would like to have more ideas on these.
This is what I want,
paper_doll('Hello') --> 'HHHeeellllllooo'
Here is my code and it doesn't work, but I have no ideas why.
def paper_doll(text):
for i in range(0,len(text)-1):
return ''.join(text[i]*3)
paper_doll('Hello')
The result became 'HHH'.
Understood the following would work,
def paper_doll(text):
result = ''
for char in text:
result += char * 3
return result
But why .join doesn't work in this case?
def paper_doll(text):
ret=[]
for i in text:
ret.append(i*3)
return ''.join(ret)
Should work. This returns each 3 letter iteration, joined together.
First, your code does not work because the return statement exits from the function on the first iteration loop, so it triples only the first letter, and that's all:
def paper_doll(text):
for i in range(0,len(text)-1): # on 1st iteration: i = 0
return ''.join(text[i]*3) # on 1st iteration: text[i] equals 'H' ==> 'HHH' is returned
Secondly, here is a solution using comprehension, which is well adapted in your case to iterate over each character of a string:
def paper_doll(text):
return ''.join(i*3 for i in text)
print(paper_doll('Hello')) # HHHeeellllllooo
Your initial problem was the return in your iteration. This short circuits the rest of the loop... as noted in other answers.
python can iterate through a string for you. Another answer using list comprehension:
def paper_doll(text):
return ''.join([char*3 for char in text])
Add to a string during the loop, return the result:
def paper_doll(text):
s = ''
for i in range(0,len(text)):
s += ''.join(text[i]*3)
return s
print(paper_doll('Hello'))
Output:
HHHeeellllllooo
(I also removed the -1 in range so you get three "o"s)
This question already has answers here:
How to remove items from a list while iterating?
(25 answers)
Correct code to remove the vowels from a string in Python
(13 answers)
Closed 6 years ago.
I just started to learn Python in codacademy. I was trying to do anti-vowel function, but found the following problem with 'u'.
def anti_vowel(text):
a = []
for i in text:
a.append(i)
for item in a:
if item in "aeiouAEIOU":
a.remove(item)
print ''.join(a)
print anti_vowel("Hey You!")
print anti_vowel("Hey look Words!")
print anti_vowel("aeiouAEIOU")
It printed
"Hy Yu!"
"Hy lk Words!"
"eoAIU"
Instead of
"Hy Y!"
"Hy lk Wrds!"
""
Somehow, some vowels was not removed es expected.
I found many alternatives for the function.
However, please help me identify the mistake of the current code.
There's no need to use remove, and there's no need to iterate twice. Rather, as you iterate, check whether the item is a vowel and only append if it is not.
def anti_vowel(text):
a = []
for i in text:
if i not in "aeiouAEIOU":
a.append(i)
print ''.join(a)
When you look very closely at the remaining vowels, you can see that all those vowels remain that immediately follow one another. In your last example, a (removed) e (stays) i (removed) o (stays) and so on.
This is because you are iterating over a list and at the same time you are modifying it.
To solve the problem, you should make a copy of the list. Then you can iterate over the original one while modifying the copy.
Removing items while iterating is not a good idea.
Do it in one line with a generator comprehension passed to str.join
def anti_vowel(text):
return ''.join(item for item in text if item not in "aeiouAEIOU")
or maybe more performant using a set for faster letter lookup (not sure converting to lowercase would speed this up since it creates a new string for that)
s=set("aeiouAEIOU")
def anti_vowel(text):
return ''.join(item for item in text if item not in s)
Like others have already stated, you are modifying your list while iterating through it. I did want to suggest a python built-in option for this task, though for 3.x > Python > 2.6:
print "Hey You!".translate(None, "aeiouAEIOU")
In Python 3.x you'll need to take account for the standard Unicode string and translate it first:
translation = dict.fromkeys(map(ord, "aeiouAEIOU"), None)
print("Hey You!".translate(translation))
def anti_vowel(text):
a = []
for i in text:
a.append(i)
b = a[:]
for item in a:
if item in "aeiouAEIOU":
b.remove(item)
print (''.join(b))
print (anti_vowel("Hey You!"))
print (anti_vowel("Hey look Words!"))
print (anti_vowel("aeiouAEIOU"))
Why not try recursively like this?
def anti_vowel(s):
if not s:
return s
elif s[0] in "aeiouAEIOU":
return anti_vowel(s[1:])
return s[0] + anti_vowel(s[1:])
print (anti_vowel("Hey You!"))
print (anti_vowel("Hey look Words!"))
print (anti_vowel("aeiouAEIOU"))
Output:
Hy Y!
Hy lk Wrds!
you are removing item from list while traversing so thats creating a problem.
Moreover there is no need to traverse the so many times.
you could use:
def anti_vowel(text):
a = []
for i in text:
if i not in "aeiouAEIOU":
a.append(i)
print ''.join(a)
or I would say instead of using list use string like this :
def anti_vowel(text):
a = ""
for item in text:
if item not in "aeiouAEIOU":
a+=item
print a
Edited:
using ''.join(list) is faster than using string cancatenation as pointed out by #jean in the comment section.
You could also join the result of a list comprehension, like:
def anti_vowel(text):
return "".join([char for char in text if char not in "aeiouAEIOU"])
Be sure to let your functions return their results if you want the function to do more than just printing to the terminal (for example if you want to use the returned value somehow). There's no need to print the results of a function that prints its result and returns None (which is the case if there are no return statements inside).
The [char for char in text ...] part of the list comprehension is simply a for loop over the characters in the string named text. The [... if char not in "aeiouAEIOU"] excludes the characters who are present in the "aeiouAEIOU" string. Finally, "".join([ ... ]) merges the non-excluded characters together to form a string which by the return statement is returned.
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
I have a feeling my question is pretty basic, as I am a first semester computer science student.
I have been asked to return the substring formed before a digit in a string similar to "abcd5efgh". The idea is to use a function to give me "abcd". I think I need to use .isdigit, but I'm not sure how to turn it into a function. Thank you in advance!
It could be done with regexp, but if you already discovered isdigit, why not use it in this case?
You can modify the last return s line to return something else if no digit is found:
def string_before_digit(s):
for i, c in enumerate(s):
if c.isdigit():
return s[:i]
return s # no digit found
print(string_before_digit("abcd5efgh"))
I am also currently a student and this is how i would approch this problem:
*For my school we are not allowed to use built in function like that in python :/
def parse(string):
newstring = ""
for i in string:
if i >= "0" and i <= "9":
break
else:
newstring += i
print newstring #Can use return if your needing it in another function
parse("abcd5efgh")
Hope this helps
A functional approach :)
>>> from itertools import compress, count, imap
>>> text = "abcd5efgh"
>>> text[:next(compress(count(), imap(str.isdigit, text)), len(text))]
'abcd'
The code is below will give you the first non digit part by using regular expression.
import re
myPattern=re.compile('[a-zA-Z]*')
firstNonDigitPart=myPattern.match('abcd5efgh')
firstNonDigitPart.group()
>>> 'abcd'
If you are not allowed to use regexes, maybe because they told you to do it explicitly by hand, you can do it like this:
def digit_index(s):
"""Helper function."""
# next(..., -1) asks the given iterator for the next value and returns -1 if there is none.
# This iterator gives the index n of the first "true-giving" element of the asked generator expression. True-giving is any character which is a digit.
return next(
(n for n, i in enumerate(i.isdigit() for i in "abc123") if i),
-1)
def before_digit(s):
di = digit_index(s)
if di == -1: return s
return s[:di]
should give you your wanted result.
A quite simple one-liner, using isdigit :)
>>> s = 'abcd5efgh'
>>> s[:[i for i, j in enumerate([_ for _ in s]) if j.isdigit()][0]]
'abcd'
An itertools approach:
>>> from itertools import takewhile
>>> s="abcd5efgh"
>>> ''.join(takewhile(lambda x: not x.isdigit(), s))
'abcd'