Can it be done with recursion? - python

im trying to make my program run as i want it to, but i have some trouble with that, hope someone can help with that.
I wrote a program that takes a list of chars and assembles them to create words. Word ends when there is a " " in list. So it looks like that:
inp = ['r','e', 'e', 'l', ' ', 'y', 'e', 'l', 'l', 'o', 'w', ' ', 'g', 'e', 'l',' ', 'p','e','e','k']
outp = ['reel', 'yellow', 'gel', 'peek']
The code looks like this:
def mer(inp, outp=[]):
tail = 0
for item in inp:
if item == (" "):
inp[:tail] = ["".join(inp[:tail])]
outp.append(inp.pop(0))
inp.remove(item)
if ((" ") in inp) == False:
inp[:] = ["".join(inp[:])]
outp.append(inp.pop(0))
tail +=1
And now to get the output (in the case with the input like on top) i need to call mer two times. Is there a way to make it run untill the input list is empty, or maybe use a recursion?
It's just a programming exercise, so it can be probably all done better, but for now thats all i need.

You can use join and split:
>>> ''.join(inp).split()
['reel', 'yellow', 'gel', 'peek']
# recursion
from itertools import takewhile
def fun(x):
if not x:
return
y = list(takewhile(lambda i:i!=' ', x))
yield ''.join(y)
for z in fun(x[len(y)+1:]):
yield z
list(fun(['r','e', 'e', 'l', ' ', 'y', 'e', 'l', 'l', 'o', 'w', ' ', 'g', 'e', 'l',' ', 'p','e','e','k']))

I know you asked for a method using recursion, but the most pythonic method in this case is to join the characters together, then split them.
outp = "".join(input).split(" ")

And now to get the output (in the case with the input like on top) i need to call mer two times.
The problem with your algorithm is that you are modifying the list while you iterate over it. This is a naughty and unsafe thing to be doing.
After "reel" is put into outp, inp is ['y', 'e', 'l', 'l', 'o', 'w', ' ', 'g', 'e', 'l',' ', 'p','e','e','k']. But the next character that will be examined by the loop is - at least in the CPython implementation - not the 'y' of 'yellow', but the 'w'. This is because the iteration internally stores an index (which happens to be in sync with the tail variable that you update manually) and uses that to grab elements. The listiterator created behind the scenes to implement the for-loop is utterly unaware of changes to the list that it's iterating over, and thus can't adjust to keep the "same position" (and who knows what you really mean by that, anyway?).
You can see this for yourself if you add a couple of "trace" print statements to the code to show the state of the variables at various points.
Anyway, since the iterator is at the 'w' at this point, it will find the space next and extract 'yellow' just fine; but next it will move to the 'k' of "peek", missing the space after 'gel', and it won't run any of the code in your second if-case, either, because the space between 'gel' and 'peek' is still in the buffer (you didn't really think clearly enough about the real end condition).
If you really, really want to do everything the hard way instead of just writing ''.join(inp).split(' '), you could fix the problem by tracking a beginning-of-word and end-of-word index, slicing out sublists, joining them and putting the resulting words into the output, and leaving the input alone. While we're at it:
functions should use the return value to return data; passing in an outp parameter is silly - let's just return a list of words.
We can use the built-in enumerate function to get indices that match up with the list elements as we iterate.
I have no idea what "mer" means.
You use way too many parentheses, and comparing to boolean literals (True and False) is poor style.
So, the corrected code using the original algorithm:
def words_from(chars):
begin = 0 # index of beginning of current word
result = [] # where we store the output
for i, char in enumerate(chars):
if char == ' ':
result.append(''.join(chars[begin:i]))
begin = i + 1
# At the end, make one more word from the chars after the last space.
result.append(''.join(chars[begin:]))
return result

You should definitely use join and split for this, but since the question specifically asks for a recursive solution, here is an answer that uses one.
This is meant as an exercise in recursion only, this code should not be used.
def join_split(inp, outp=None):
if not inp:
return outp
if inp[0] == ' ':
return join_split(inp[1:], (outp or ['']) + [''])
if outp is None:
return join_split(inp[1:], [inp[0]])
outp[-1] += inp[0]
return join_split(inp[1:], outp)
>>> join_split(['r','e', 'e', 'l', ' ', 'y', 'e', 'l', 'l', 'o', 'w', ' ', 'g', 'e', 'l',' ', 'p','e','e','k'])
['reel', 'yellow', 'gel', 'peek']

Related

Can you add characters from a string to a list?

I'm wondering if it's possible to take a string e.g. str(input()) and split it into individual chars, then add them to a list. I'm trying to make a simple script (something similar to a hangman game) and at the beginning I wrote this:
x=input('Choose word: ').lower()
letters=[]
letters.append(list(x))
print(letters)
but this code appends the whole list to a list and not individual chars
Edit: this outputs [['o', 'u', 't', 'p', 'u', 't']] meaning that the whole list got appended as one item, but I want this to output ['o', 'u', 't', 'p', 'u', 't'], how do I make it append individual chars and not the whole list
You are simply wrapping the char list in another list.
Try this one-liner instead:
print(list(x))
If you want to remove a character:
letters = list(x)
letters.remove('o')
print(letters)
Use extend instead of append function.
#Extend
x=input('Choose word: ').lower()
letters=[]
letters.extend(list(x))
print(letters)
# ['p', 'y', 't', 'h', 'o', 'n']
And to remove a character from a list while retaining position as blank after removing, use replace while within a list:
y=input("Choose a letter to remove: ").lower()
removed=[s.replace(y,'') for s in letters]
print(removed)
#['p', '', 't', 'h', 'o', 'n']
I hope this help, unless its different from what you want. Then let me know. Otherwise, happy coding!
You don't need to create an empty list and then populate it with individual letters. Simply apply the list() function directly for the user input to create it:
letters = list(input('Choose word: ').lower())
print(letters)
For adding letters from the other user input, use the same approach with the .extend() method:
letters.extend(input('Choose word: ').lower()) # No need to use list() here
A simple one liner:
x = input().lower().split()
print(x)
here we are taking the input and then we are converting to lowercase and then using the split function which will split the string on white spaces you can split the string on whatever string you feel like just give the string you want to split on as the argument in the split function for example:
x = input().lower().split(',')
print(x)
this will split on the ',' so you can give the input in csv format
You may use the + operator (preferably in the form of an augmented assignment statement, i.e. +=, for extending the list to an iterable.
No need to use the list() function here, because the string is iterable:
letters = []
letters += input('Choose word: ').lower()
print(letters)
this outputs [['o', 'u', 't', 'p', 'u', 't']] meaning that the whole
list got appended as one item, but i want this to output ['o', 'u', 't', 'p', 'u', 't']
Based on you comment, you can use:
x = [*input('Choose word: ').lower()]
print(x)
# ['p', 'y', 't', 'h', 'o', 'n']
Demo

The Palindromes, Python, Problems

I am a newbie python coder learning for fun. I am wondering why this program has difficulty outputting the correct output. I believe the problem lies with the very end of the program "if list == inverselist:".
I always get an output telling me the word is a palindrome even when it is not (e.g. tigers)
#Exercise 6 - Ask the user for a string and print out whether this string is a palindrome or not. (A palindrome is a string that reads the same forwards and backwards.)
possiblepalindrome = str(input("Put in the possible palindromic statement here: "))
print(possiblepalindrome)
list=[]
for x in possiblepalindrome: #put each individual string character in a new list as its own element
list.append(x)
print ('this is list', list)
for x in list: #Removes all spaces so multiple word/sentences can be palindrome
if x is ' ':
list.remove(' ')
print('this is with removed spaces' , list)
def reverselist(argument): #This is a function. We put in some list, then the list is reversed, and is spat back out
argument.reverse()
return argument
inverselist = reverselist(list) #We use the reverselist function to make an inverse list of the palindrome
print('this is inverselist',inverselist)
if list == inverselist:
print('Congratulations ', '"', possiblepalindrome, '"', ' is a palindrome!')
else:
print('Unfortunately', '"', possiblepalindrome, '"', 'is not a palindrome.')
list and inverselist have the reference to the same list. You need to clone the list.
Just change the reverselist function
def reverselist(argument): #This is a function. We put in some list, then the list is reversed, and is spat back out
li_copy = []
li_copy.extend(argument)
li_copy.reverse()
return li_copy
Entire code:
possiblepalindrome = str(input("Put in the possible palindromic statement here: "))
print(possiblepalindrome)
list=[]
for x in possiblepalindrome: #put each individual string character in a new list as its own element
list.append(x)
print ('this is list', list)
for x in list: #Removes all spaces so multiple word/sentences can be palindrome
if x is ' ':
list.remove(' ')
print('this is with removed spaces' , list)
def reverselist(argument): #This is a function. We put in some list, then the list is reversed, and is spat back out
li_copy = []
li_copy.extend(argument)
li_copy.reverse()
return li_copy
inverselist = reverselist(list) #We use the reverselist function to make an inverse list of the palindrome
print('this is inverselist',inverselist)
if list == inverselist:
print('Congratulations ', '"', possiblepalindrome, '"', ' is a palindrome!')
else:
print('Unfortunately', '"', possiblepalindrome, '"', 'is not a palindrome.')
You posted far too much code, and didn't bother to test it. reverselist doesn't work the way you expect. It reverses the input list, which is a mutable object.
def reverselist(argument): #This is a function. We put in some list, then the list is reversed, and is spat back out
argument.reverse()
return argument
word = list("Hello, world")
print(word)
inverseword = reverselist(word)
print(word, '\n', inverseword)
Output:
['H', 'e', 'l', 'l', 'o', ',', ' ', 'w', 'o', 'r', 'l', 'd']
['d', 'l', 'r', 'o', 'w', ' ', ',', 'o', 'l', 'l', 'e', 'H']
['d', 'l', 'r', 'o', 'w', ' ', ',', 'o', 'l', 'l', 'e', 'H']
In short, you reversed the list, and then compared the result to itself.
Notes:
Do not use a pre-defined name as a variable. I changed list to word.
Look up how to reverse a sequence. We expect you to do appropriate research before posting here.
Learn to test code blocks. See this lovely reference for debugging help.
Your function can be simply:
return argument[::-1]
First, naming your list list is tempting but dangerous in Python as you will not be able to call the list() constructor
Basically your code could be reduced like this
possiblepalindrome = str(input("Put in the possible palindromic statement here: "))
print(possiblepalindrome)
normal_list = list(possiblepalindrome.remove(" "))
inverselist= list(reversed(possiblepalindrome))
print('this is inverselist',"".join(inverselist))
if list == inverselist:
print('Congratulations ', '"', possiblepalindrome, '"', ' is a palindrome!')
else:
print('Unfortunately', '"', possiblepalindrome, '"', 'is not a palindrome.')
To check if a string is a palindrome:
v = str(input("Put in the possible palindromic statement here: "))
print (v == (v[::-1]))
Just take the input, compare to the reverse. If those are equal you get a True (so it is a palindrome) otherwise a False.

i want to remove empty string from a list

can someone please tell me why I cant remove the empty string by using following code?
numlist = list()
tim = "s x s f f f"
timo = tim.strip()
for line in timo:
numlist.append(line)
list(filter(None, numlist))
print(numlist)
output: ['s', ' ', 'x', ' ', 's', ' ', 'f', ' ', 'f', ' ', 'f']
desired output: ['s', 'x', 's', 'f', 'f', 'f']
Use split not strip. strip is for removing leading and trailing characters
In [35]: tim = "s x s f f f"
In [36]: tim.split()
Out[36]: ['s', 'x', 's', 'f', 'f', 'f']
You forgot to assign the result of the filtering back to numlist, so it made the new list and discarded it. Just make the line:
numlist = list(filter(None, numlist))
That said, it wouldn't have done what you wanted, because a string of a single space is still truthy. If you want to exclude spaces as truthy, a simple tweak would be:
numlist = list(filter(str.strip, numlist))
Or simplifying further (but with different behavior if the input isn't always single characters with space separation), replace the entirety of your code with just:
tim = "s x s f f f"
numlist = tim.split()
print(numlist)
as no-arg split will split on whitespace, remove leading and trailing whitespace, and return the list of non-whitespace components as a single efficient action.

Can this function return an int value by linking the elements of a list?

I am creating a function in order to develop a tiny word game. When I was creating it I got stuck when I tried to write the body. I was looking for information about Python and if I can write a return statement . It seems that it is possible but I didn't find out anything clear about that. This is my body function: This is my current progress: Am I close? or Should I try another method?
def num_words_on_board(board, words):
""" (list of list of str, list of str) -> int
Return how many words appear on board.
>>> num_words_on_board([['A', 'N', 'T', 'T'], ['X', 'S', 'O', 'B']], ['ANT', 'BOX', 'SOB', 'TO'])
3
"""
count = 0
for word_list in board:
if words in ''.join(word_list):
count = count + 1
return count
Your question is lacking in explanation, but I'll answer the best I understood.
I think you are trying to do something like a wordsearch solver, mixed with a scramble puzzle?
Anyways, my recommendation is to make multiple functions for everything you need to solve. For example:
The way I see it, you need to know if the letters in the board can make up each of the words in the words variable. That can be done by one function. If you don't really need the order of the word, just the length, then we can do it like this.
def same (word, letters):
temp = []
for every_letter in word:
if every_letter in letters and every_letter not in temp:
temp.append(every_letter)
return len(temp) >= len(word)
This function takes only one word and a "bunch of letters" (for example a list from board ;) ) as parameters, then the function compares each letter in the word against each letter in the "bunch of letters" and if it finds a match it adds it to a temp variable, at the end of the iterations if the temp variable has at least the same count of letters as the initial `word' then it's safe to say that the word can be built.
*there is a problem with this function. If the original word has repeated letters, for example the word "butter" then this function will not work, but since this is not your case we are good to continue.
For the second part we have to use that function for every word in board so we'll use another function for that:
def num_words_on_board(board, words):
count = 0
for word in words:
for letters in board:
if same(word, letters):
count += 1
print(count) # This is not needed, just here for testing.
return count
And there we go. This function should return the count which is 3. I hope this helps you.
(if anyone wanna correct my code please feel free, it's not optimal by any means. Just thought it would be easy to understand like this, rather than the answer in the duplicate question mentioned by Stefan Pochmann)
:)
I had a previous function can I use it in order to create this new one?.
My previous function is this:
def board_contains_word(board, word):
""" (list of list of str, str) -> bool
Return True if and only if word appears in board.
Precondition: board has at least one row and one column.
>>> board_contains_word([['A', 'N', 'T', 'T'], ['X', 'S', 'O', 'B']], 'ANT')
True
>>> board_contains_word([['A', 'N', 'T', 'T'], ['X', 'S', 'O', 'B']], 'NNT')
False
>>> board_contains_word([['A', 'N', 'T', 'T'], ['X', 'S', 'O', 'B']], 'NTT')
True
"""
for word_list in board:
if word in ''.join(word_list):
return True
return False

Python: How to print a list with labels for each item within the list

I am doing a python project for my Intro to CSC class. We are given a .txt file that is basically 200,000 lines of single words. We have to read in the file line by line, and count how many times each letter in the alphabet appears as the first letter of a word. I have the count figured out and stored in a list. But now I need to print it in the format
"a:10,898 b:9,950 c:17,045 d:10,596 e:8,735
f:11,257 .... "
Another aspect is that it has to print 5 of the letter counts per line, as I did above.
This is what I am working with so far...
def main():
file_name = open('dictionary.txt', 'r').readlines()
counter = 0
totals = [0]*26
alphabet = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z']
for i in file_name:
for n in range(0,26):
if i.startswith(alphabet[n]):
totals[n] = totals[n]+1
print(totals)
main()
This code currently outputs
[10898, 9950, 17045, 10675, 7421, 7138, 5998, 6619, 6619, 7128, 1505, 1948, 5393, 10264, 4688, 6079, 15418, 890, 10790, 20542, 9463, 5615, 2924, 3911, 142, 658]
I would highly recommend using a dictionary to store the counts. It will greatly simplify your code, and make it much faster. I'll leave that as an exercise for you since this is clearly homework. (other hint: Counter is even better). In addition, right now your code is only correct for lowercase letters, not uppercase ones. You need to add additional logic to either treat uppercase letters as lowercase ones, or treat them independently. Right now you just ignore them.
Having said that, the following will get it done for your current format:
print(', '.join('{}:{}'.format(letter, count) for letter, count in zip(alphabet, total)))
zip takes n lists and generates a new list of tuples with n elements, with each element coming from one of the input lists. join concatenates a list of strings together using the supplied separator. And format does string interpolation to fill in values in a string with the provided ones using format specifiers.
python 3.4
the solution is to read the line of the file into words variable below in cycle and use Counter
from collections import Counter
import string
words = 'this is a test of functionality'
result = Counter(map(lambda x: x[0], words.split(' ')))
words = 'and this is also very cool'
result = result + Counter(map(lambda x: x[0], words.split(' ')))
counters = ['{letter}:{value}'.format(letter=x, value=result.get(x, 0)) for x in string.ascii_lowercase]
if you print counters:
['a:3', 'b:0', 'c:1', 'd:0', 'e:0', 'f:1', 'g:0', 'h:0', 'i:2', 'j:0', 'k:0', 'l:0', 'm:0', 'n:0', 'o:1', 'p:0', 'q:0', 'r:0', 's:0', 't:3', 'u:0', 'v:1', 'w:0', 'x:0', 'y:0', 'z:0']

Categories

Resources