How would you make a list of all the possible substrings in a string using recursion? (no loops) I know that you can recurse using s[1:] to cut off the first position and s[:-1] to cut off the last position. So far I have come up with this:
def lst_substrings(s):
lst = []
if s == "":
return lst
else:
lst.append(s)
return lst_substrings(s[1:])
but this would only make a list of all the substrings that are sliced by the first position if it worked
Fun problem, here's my solution - feedback appreciated.
Output
In [73]: lstSubStrings("Hey")
Out[73]: ['', 'y', 'H', 'Hey', 'He', 'e', 'ey']
Solution
def lstSubStrings(s):
# BASE CASE: when s is empty return the empty string
if(len(s) is 0):
return [s]
substrs = []
# a string is a substring of itself - by the definition of subset in math
substrs.append(s)
# extend the list of substrings by all substrings with the first
# character cut out
substrs.extend(lstSubStrings(s[1:]))
# extend the list of substrings by all substrings with the last
# character cut out
substrs.extend(lstSubStrings(s[:-1]))
# convert the list to `set`, removing all duplicates, and convert
# back to a list
substrs = list(set(substrs))
return substrs
EDIT: Duh. Just realized now that practically the same solution has been posted by someone who was quicker than me. Vote for his answer. I'll leave this as it is a bit more concise and in case you want to sort the resulting list by substring length. Use len(item, item), i.e. leave the - sign, to sort in ascending order.
This will do:
def lst_substrings(s):
lst = [s]
if len(s) > 0:
lst.extend(lst_substrings(s[1:]))
lst.extend(lst_substrings(s[:-1]))
return list(set(lst))
sub = lst_substrings("boby")
sub.sort(key=lambda item: (-len(item), item))
print(sub)
Output is:
['boby', 'bob', 'oby', 'bo', 'by', 'ob', 'b', 'o', 'y', '']
Related
I am making a program that has two lists (in Python), and each list contains 5 different letters. How do I make it so that any index number I choose for both lists gets compared and uppercase a letter if the condition is true? If the first two values in the list are the same (in my case a lowercase letter), then I want the letter in the second list to become uppercase.
example/attempt (I don't know what I'm doing):
if list1[0] = list2[0]:
upper(list2[0])
Without an example of you input and output, it's difficult to understand what your goal is, but if your goal is to use .upper() on any string in list2 where list1[i] and list2[i] are equal, you can use a combination of zip and enumerate to compare, and then assign the value of list2[i] to the uppercase string like so:
list1 = ['a', 'b', 'c']
list2 = ['a', 'p', 'q']
for i, (x, y) in enumerate(zip(list1, list2)):
if x == y:
list2[i] = y.upper()
print(list2)
Output:
['A', 'p', 'q']
I think you could use something like this:
def compare_and_upper(lst1, lst2):
for i in range(len(lst1)):
if lst1[i].upper() == lst2[i].upper():
return lst1[i].upper()
return None
This is not a full solution of your problem, more of a representation of how to do the comparisons, which you can then reuse / modify to do the solution you want in the end.
import string
from random import choices
def create_random_string(str_len=10):
# k = the number of letters that we want it to return.
return "".join(choices(string.ascii_lowercase, k=str_len))
def compare(str_len=10):
# Create the two strings that we want to compare
first_string = create_random_string(str_len)
second_string = create_random_string(str_len)
# comp_string will hold the final string that we want to return.
comp_string = ""
# Because the length of the strings are based on the variable str_len,
# we can use the range of that number to iterate over our comparisions.
for i in range(str_len):
# Compares the i'th position of the strings
# If they match, then add the uppercase version to comp_string
if first_string[i] == second_string[i]:
comp_string += first_string[i].upper()
else:
comp_string += "-"
return comp_string
for _ in range(10):
print(compare(20))
Sample output:
--------------------
---AS---D---------D-
----W--Q--------E---
--------------------
-----------------E--
------T-------------
--------------------
-------------P------
-----S--------------
--B-----------------
The list ['a','a #2','a(Old)'] should become {'a'} because '#' and '(Old)' are to be excised and a list of duplicates isn't needed. I struggled to develop a list comprehension with a generator and settled on this since I knew it'd work and valued time more than looking good:
l = []
groups = ['a','a #2','a(Old)']
for i in groups:
if ('#') in i: l.append(i[:i.index('#')].strip())
elif ('(Old)') in i: l.append(i[:i.index('(Old)')].strip())
else: l.append(i)
groups = set(l)
What's the slick way to get this result?
Here is general solution, if you want to clean elements of list lst from parts in wastes:
lst = ['a','a #2','a(Old)']
wastes = ['#', '(Old)']
cleaned_set = {
min([element.split(waste)[0].strip() for waste in wastes])
for element in arr
}
You could write this whole expression in a single set comprehension
>>> groups = ['a','a #2','a(Old)']
>>> {i.split('#')[0].split('(Old)')[0].strip() for i in groups}
{'a'}
This will get everything preceding a # and everything preceding '(Old)', then trim off whitespace. The remainder is placed into a set, which only keeps unique values.
You could define a helper function to apply all of the splits and then use a set comprehension.
For example:
lst = ['a','a #2','a(Old)', 'b', 'b #', 'b(New)']
splits = {'#', '(Old)', '(New)'}
def split_all(a):
for s in splits:
a = a.split(s)[0]
return a.strip()
groups = {split_all(a) for a in lst}
#{'a', 'b'}
In the challenge you are asked to find the length of the longest substring that consists of the same letter. For example, line "aaabbcaaaa" contains four substrings with the same letters "aaa", "bb","c" and "aaaa". The last substring is the longest one which makes it an answer. Input: String. Output: Int. Example:
long_repeat('sdsffffse') == 4
long_repeat('ddvvrwwwrggg') == 3
Here is my code :
def long_repeat(text):
text = list(text)
counter = []
c = []
for i in range(len(text)):
if text[0] == text[1]:
c.append(text.pop(0))
else:
counter.append(c)
c = []
print text # should be empty
print counter # should contain a lists of the repeated letters
Output:
>>>long_repeat('aaabbccc')
['a', 'b', 'b', 'c', 'c', 'c', 'c']
[['a', 'a'], [], [], [], [], [], []]
why the loop stopes when it finishes the first letter which is 'a' in this case?
The loop does not stop. Your else statement does not move the list forward (no pop here). By the way, your logic is not quite correct. And also, it is not a good idea to pop the character and then collect it each turn. You can use integers to record all necessary information you need, including position, current count, maximum count and etc.
When test[0] != text[1] e.g when input is at "ab" you aren't appending the a to the c variable
In addition, Python string has no "pop" method hence why it's exiting out (pay close attention to error returned).
Use something like this for pop
c.append(text[-1])
text = text[:-1]
this is a question I have from one of my review packages and I'm pretty stumped. This is the description
"Return a list of m strings, where m is the length of a longest string
in strlist, if strlist is not empty, and the i-th string returned
consists of the i-th symbol from each string in strlist, but only from
strings that have an i-th symbol, in the order corresponding to the
order of the strings in strlist.
Return [] if strlist contains no nonempty strings."
This is the example
transpose(['transpose', '', 'list', 'of', 'strings'])
['tlos', 'rift', 'asr', 'nti', 'sn', 'pg', 'os', 's', 'e']
And this is the given format/style you gotta follow
# create an empty list to use as a result
# loop through every element in the input list
# loop through each character in the string
# 2 cases to deal with here:
# case 1: the result list has a string at the correct index,
# just add this character to the end of that string
# case 2: the result list doesn't have enough elements,
# need to create a new element to store this character
I got upto the "2 cases to deal with here:" part and then I got stuck, this is what I have so far
result = []
for index in strlist:
for char in range (len(index)):
this should work:
def transpose(strlist):
# create an empty list to use as a result
result = []
# loop through every element in the input list
for i in range(len(strlist)):
# loop through each character in the string
for j in range(len(strlist[i])):
# 2 cases to deal with here:
if len(result) > j:
# case 1: the result list has a string at the correct index,
# just add this character to the end of that string
result[j] = result[j] + strlist[i][j]
else:
# case 2: the result list doesn't have enough elements,
# need to create a new element to store this character
result.append(strlist[i][j])
return result
print(transpose(['transpose', '', 'list', 'of', 'strings']))
it outputs: ['tlos', 'rift', 'asr', 'nti', 'sn', 'pg', 'os', 's', 'e']
there are more pythonic ways to achieve it, but the shown code matches your given format/style
Question: DO NOT USE SETS IN YOUR FUNCTION: Uses lists to return a list of the common letters in the first and last names (the intersection) Prompt user for first and last name and call the function with the first and last names as arguments and print the returned list.
I can't figure out why my program is just printing "No matches" even if there are letter matches. Anything helps! Thanks a bunch!
Code so far:
import string
def getCommonLetters(text1, text2):
""" Take two strings and return a list of letters common to
both strings."""
text1List = text1.split()
text2List = text2.split()
for i in range(0, len(text1List)):
text1List[i] = getCleanText(text1List[i])
for i in range(0, len(text2List)):
text2List[i] = getCleanText(text2List[i])
outList = []
for letter in text1List:
if letter in text2List and letter not in outList:
outList.append(letter)
return outList
def getCleanText(text):
"""Return letter in lower case stripped of whitespace and
punctuation characters"""
text = text.lower()
badCharacters = string.whitespace + string.punctuation
for character in badCharacters:
text = text.replace(character, "")
return text
userText1 = raw_input("Enter your first name: ")
userText2 = raw_input("Enter your last name: ")
result = getCommonLetters(userText1, userText2)
numMatches = len(result)
if numMatches == 0:
print "No matches."
else:
print "Number of matches:", numMatches
for letter in result:
print letter
Try this:
def CommonLetters(s1, s2):
l1=list(''.join(s1.split()))
l2=list(''.join(s2.split()))
return [x for x in l1 if x in l2]
print CommonLetters('Tom','Dom de Tommaso')
Output:
>>> ['T', 'o', 'm']
for letter in text1List:
Here's your problem. text1List is a list, not a string. You iterate on a list of strings (['Bobby', 'Tables'] for instance) and you check if 'Bobby' is in the list text2List.
You want to iterate on every character of your string text1 and check if it is present in the string text2.
There's a few non-pythonic idioms in your code, but you'll learn that in time.
Follow-up: What happens if I type my first name in lowercase and my last name in uppercase? Will your code find any match?
Prior to set() being the common idiom for duplicate removal in Python 2.5, you could use the conversion of a list to a dictionary to remove duplicates.
Here is an example:
def CommonLetters(s1, s2):
d={}
for l in s1:
if l in s2 and l.isalpha():
d[l]=d.get(l,0)+1
return d
print CommonLetters('matteo', 'dom de tommaso')
This prints the count of the common letters like so:
{'a': 1, 'e': 1, 'm': 1, 't': 2, 'o': 1}
If you want to have a list of those common letters, just use the keys() method of the dictionary:
print CommonLetters('matteo', 'dom de tommaso').keys()
Which prints just the keys:
['a', 'e', 'm', 't', 'o']
If you want upper and lower case letters to match, add the logic to this line:
if l in s2 and l.isalpha():