Converting lowercase to uppercase in Python using recursion - python

I am a student relatively new to Python, learning it through classes. We were given a question where we have a list as an input, and we have to convert each element to uppercase. Here is my code so far:
def strChange(lst):
ch=''
for i in range(len(lst)):
if lst[i]>='a' and lst[i]<='z' :
ch+=chr(ord(lst[i])-32)
return ch
caps = eval(input("Enter list: "))
caps2 = []
for i in range(len(caps)):
a = strChange(caps[i])
caps2.append(a)
print(caps2)
And it does the job... But the problem is, it is not using recursion! And I have absolutely no idea where to use it! I am open to all suggestions, but layman's terms are preferred.
Edit: adding example inputs
input: ['rohit', 'mohan', 'anjali', 'ankit', 'akshit']
output: ['ROHIT', 'MOHAN', 'ANJALI', 'ANKIT', 'AKSHIT']

It's silly, but here's how you do it. You process one character and call the function again for the rest.
def strChange(lst):
if not lst:
return ''
ch = lst[0]
if 'a' <= ch <= 'z':
ch = chr(ord(ch)-32)
return ch + strChange(lst[1:])
caps = eval(input("Enter list: "))
for word in caps:
print(strChange(word))

Maybe you can use recursion in case of nested lists? If item in list is list you call same function with it?
def strChange(lst):
for index, item in enumerate(lst):
if type(item) is list:
strChange(item)
else:
lst[index] = item.upper()
return lst

Related

How to use insert() in a for loop without making it a endless loop?

I'm trying to make a project in python so that whenever the program encounters a capital letter it makes a white space. So for example "helloThisIsMyProject" > hello This is My Project.
def project(w):
lst = []
for i in w:
lst.append(i)
for letter in lst:
if letter.isupper():
index = lst.index(letter)
lst.insert(index, " ")
continue
return "".join(lst)
print(project("helloThisIsMyProject"))
I'm having a problem with insert() and the for loop because the for loop is endlessly looping over the "T" from "This". I tried using continue to skip the letter T but it didn't fix my problem.
Those 1st three lines are simply
lst = list(w)
But you would find this more convenient:
lst = []
for letter in w:
if letter.isupper():
lst.append(" ")
lst.append(letter)
That is, rather than producing a list and going back to fix it up,
you could have it correct from the outset.
You can conditionally output a SPACE before you output the letter.
If you prefer to do it with a list comprehension,
you might enlist the aid of a helper:
def adjust(s: str) -> str:
"""Returns the input string, possibly whitespace adjusted."""
return " " + s if s.isupper() else s
lst = [adjust(letter)
for letter in w]
or more compactly:
lst = list(map(adjust, w))
You could use a join with a list comprehension that adds the space to individual characters:
def spaceCaps(w):
return "".join(" "*c.isupper()+c for c in w)
spaceCaps("helloThisIsMyProject")
'hello This Is My Project'
You could also use the sub() function from the regular expression module:
import re
def spaceCaps(w):
return re.sub("([A-Z])",r" \1",w)

Appending a char to an empty list

I am very new to programming, so sorry for a basic question. I am trying to write a function that will take a string in which words are divided by ',' and return a list of these words (the Split method). My code is:
def str_to_list(my_shop_str):
my_shop_list = ['']
word_in_list = 0
for letter in my_shop_str:
if letter != ',':
my_shop_list[word_in_list] += letter
else:
word_in_list += 1
my_shop_list + ['']
return my_shop_list
print(str_to_list("Milk,Cottage,Tomatoes")) should look like [Milk, Cottage, Tomatoes]
but I am keep getting IndexError: list index out of range.
I read some answers here and couldn't find something to work.
Can anyone explain what is wrong.
list has the method append so a solution will be something like this:
def str_to_list(my_shop_str):
my_shop_list = ['']
word_in_list = 0
for letter in my_shop_str:
if letter != ',':
my_shop_list[word_in_list] += letter
else:
word_in_list += 1
my_shop_list.append('')
return my_shop_list
PS: Do not forgot about empty spaces between words in string like "aaa, bbb, ccc" will be ['aaa', ' bbb', ' ccc'] with spaces.
def sp(s):
l =[]
while True:
comma = s.find(',')
if comma == -1:
l.append(s)
break
l.append(s[:comma])
s = s[comma+1:]
print(l)
this is a simplified version hope it helps.
Simplest Way:
We can use an inbuilt split function.
def Convert(string):
# split the string whenever "," occurs
# store the splitted parts in a list
li = list(string.split(","))
return li
# Driver code
str1 = "Hello,World"
print(Convert(str1))
Output:
["Hello", "World"]

Conceputalize breaking down a list comprehension of enumerate

I'm starting out here and love list comprehension. I found this following line of code for a practice problem of capitalizing every other letter in a string and it makes sense to me. The problem I'm hoping to get help with is figuring out how to write this code normally (for loop, if statements, etc. Beginners stuff) without list comprehension.
Here's the code that I started with that I want to break down:
s = input('Please enter a string: ')
answer = ''.join(char.upper() if idx % 2 else char.lower() for idx, char in enumerate(s))
print(answer)
And here is what I thought was a proper code to reproduce what this one above was doing:
s = input('Please enter a string: ')
for idx, char in enumerate(s):
if idx % 2:
s = char.upper()
else:
s = char.lower()
answer = ''.join(s)
print(answer)
If I were to type Hello, I should get hElLo, but instead I get o
I'd appreciate any advice or tips on how to proceed here. Thanks!
Technically you're using a generator expression, and not a list comprehension. But the result is similar in this case.
You're reading input into s, but then you're reassigning s in each iteration, and then you're joining s.
You need to have a different variable. For the input and for the capitalized list. What a generator expression does is to return one value at a time, instead of building the whole capitalized list at once. But here you will need to declare it.
Also, it doesn't make sense to assign answer in each iteration, the join is the last thing you need to do, once your capitalized list is prepared.
This should work:
toCapitalize = input('Please enter a string: ')
capitalizedList = []
for idx, char in enumerate(toCapitalize):
if idx % 2:
capitalizedList.append(char.upper())
else:
capitalizedList.append(char.lower())
answer = ''.join(capitalizedList)
print(answer)
In case this helps, I've tried to reflect what line goes with what part of the generator expression below:
for idx, char in enumerate(toCapitalize): # for idx, char in enumerate(s)
if idx % 2: capitalizedList.append(char.upper()) # char.upper() if idx % 2
else: capitalizedList.append(char.lower()) # else char.lower()
answer = ''.join(capitalizedList) # answer = ''.join()
Again, the capitalizedList variable is implicit in the generator expressions or list comprehensions.
Generator expressions
To understand generator expressions look at this code:
capitalize = 'hello'
generator = (char.upper() if idx % 2 else char.lower() for idx, char in enumerate(capitalize))
print(next(generator)) # h
print(next(generator)) # E
print(next(generator)) # l
print(next(generator)) # L
print(next(generator)) # o
print(next(generator)) # raises a StopIteration exception, we've reached the end.
Each call to next() calculates the result of the next iteration on the fly. Which is more memory efficient than building a whole list at once when you have big lists. In your case, the call to join() consumes all the generator, and joins the values returned.
As a list comprehension
Your code as a list comprehension would be:
s = input('Please enter a string: ')
answer = ''.join([ char.upper() if idx % 2 else char.lower() for idx, char in enumerate(s) ])
print(answer)
As I explained above, the difference is that here we're building a whole list at once, the generator is only returning one value at a time.
Your code as a generator
And finally, to be technically correct your code would be equivalent to this:
def generator(s):
for idx, char in enumerate(s):
if idx % 2:
yield char.upper()
else:
yield char.lower()
answer = ''.join(generator(s))
print(answer)
That's how you build a generator in Python.

Is there a better way to accomplish this python excercise? (Beginner)

I'm just starting to learn Python and I'm going through an exercise at the end of a chapter. So far, all I've learned about in the book is the very basics, flow control, functions, and lists.
The exercise is:
Comma Code
Say you have a list value like this:
spam = ['apples', 'bananas', 'tofu', 'cats']
Write a function that takes a list value as an argument and returns
a string with all the items separated by a comma and a space, with "and"
inserted before the last item. For example, passing the previous spam list to
the function would return 'apples, bananas, tofu, and cats'. But your function
should be able to work with any list value passed to it.
To solve this, I use the following code (python 3.x.x). I'm wondering if there is a better way to do this. It took a little trial and error, but I fumbled through it until I got this:
myList = ['apples', 'bananas', 'tofu', 'cats']
myList2 = ['apples', 'bananas', 'tofu', 'cats', 'added1', 'added2']
def listFunc(List):
x = 0
for i in List:
x += 1
if x < len(List):
print(i, end=' ')
elif x == len(List):
print('and ' + i)
listFunc(myList2)
Another way to accomplish this would be to use slices and joins:
def listFunc(lst):
if len(lst) == 0: return ''
if len(lst) == 1: return lst[0]
return ", and ".join([", ".join(lst[:-1]), lst[-1]])
Here's a more readable version of the above function using the same core concepts.
def listFunc(lst):
if len(lst) == 0: return '' #no elements? empty string
if len(lst) == 1: return lst[0] #one element? no joining/separating to do, just give it back
firstPart = lst[:-1] #firstPart is now everything except the last element
retFirst = ", ".join(firstPart) #retFirst is now the first elements joined by a comma and a space.
retSecond = ", and " + lst[-1] #retSecond is now ", and [last element]"
return retFirst + retSecond;
The only potentially confusing bits here I think are the slice syntax, negative indices, and string.join
The code lst[:-1] means get everything in lst excepting the last element This is a list slice
The code lst[-1] means get the last element in lst This is negative indexing
And finally, the code ", ".join(firstPart) means get a string containing each element in firstPart separated by a comma and a space
Here is a simple version of the function that doesn't use anything very "fancy" and should be understandable by a beginner. Slicing is probably the most advanced stuff here but should be ok if you went through lists. It also handles two special cases of an empty list and one-item list.
def listFunc(List):
if len(List) == 0: return ''
if len(List) == 1: return List[0]
value = List[0]
for item in List[1:-1]:
value = value + ', ' + item
return value + ', and ' + List[-1]
This is not the way you would normally do it in Python but should be good for learning purposes.
Let's have fun with Python 3 and keep it simple:
def listFunc(myList):
*rest, last = myList
return ", ".join(rest) + (", and " if rest else "") + last
You can make it slightly shorter using enumerate:
def printList():
# x will be the string in the list, y will be an integer
aString = ""
for (y,x) in enumerate(myList):
if y < len(myList) - 1:
aString = aString + x + ", "
else:
aString = aString + "and " + x
.
.
.

Reference next item in list: python

I'm making a variation of Codecademy's pyglatin.py to make a translator that accepts and translates multiple words. However, I'm having trouble translating more than one word. I've been able to transfer the raw input into a list and translate the first, but I do not know how to reference the next item in the list. Any help would be greatly appreciated.
def piglatin1():
pig = 'ay'
original = raw_input('Enter a phrase:').split(' ')
L = list(original)
print L
i = iter(L)
item = i.next()
for item in L:
if len(item) > 0 and item.isalpha():
word = item.lower()
first = word
if first == "a" or first == "e" or first == "i" or first == "o" or first =="u":
new_word = word + pig
print new_word
else:
new_word = word[1:] + word[0:1] + pig
# first word translated
L = []
M = L[:]
L.append(new_word)
print L # secondary list created.
again = raw_input('Translate again? Y/N')
print again
if len(again) > 0 and again.isalpha():
second_word = again.lower()
if second_word == "y":
return piglatin()
else:
print "Okay Dokey!"
else:
print 'Letters only please!'
return piglatin1()
I was working on this problem recently as well and came up with the following solution (rather than use range, use enumerate to get the index).
for index, item in enumerate(L):
next = index + 1
if next < len(L):
print index, item, next
This example shows how to access the current index, the current item, and then the next item in the list (if it exists in the bounds of the list).
Here are a few things to note that might help.
The lines i = iter(L) and item = i.next() are unnecessary. They have no effect in this method because you are redefining item immediately afterwards in the line for item in L. Go ahead and comment out those two lines to see if it makes any changes in your output.
The looping construct for item in L will go once over every item in the list. Whatever code you write within this loop will be executed once for each item in the list. The variable item is your handle to the list element of an iteration.
If, during any iteration, you really do want to access the "next" element in the list as well, then consider using a looping construct such as for i in range(0,len(L)). Then L[i] will be the current item and L[i+1] will you give the subsequent item.
There are some slight issues with the code but I think there is one main reason why it will not repeat.
In order to process the entire string the
again = raw_input('Translate again? Y/N')
and it's succeeding lines should be brought outside the for statement.
Also you appear to be setting L to an empty string inside the loop:
L = []
The following is a modified version of your code which will loop through the entire sentence and then ask for another one.
def piglatin():
pig = 'ay'
while True:
L = raw_input('Enter a phrase:').split(' ')
M = []
for item in L:
if len(item) > 0 and item.isalpha():
word = item.lower()
first = word
if first == "a" or first == "e" or first == "i" or first == "o" or first =="u":
new_word = word + pig
print new_word
else:
new_word = word[1:] + word[0:1] + pig
M.append(new_word)
else:
print 'Letters only please!'
print M # secondary list created.
again = raw_input('Translate again? Y/N')
print again
if len(again) > 0 and again.isalpha():
second_word = again.lower()
if second_word == "n":
print "Okay Dokey!"
break
Changes made:
You don't need to cast the return of the split to a list. The split
return type is a list.
It isn't necessary to make an iterator, the for loop will do this for you.
I removed the function as the return type. I'm assuming you were attempting some form of recursion but it isn't strictly necessary.
Hope this helps.
Step by step:
If you set variable original in this way:
original = raw_input('Enter a phrase:').split()
it will be already a list, so need to additional assignment.
What is the purpose of these lines?
i = iter(L)
item = i.next()
In a loop, you assign variable to the word, when it is actually only the first letter of the word, so it’ll be better like this: first = word[0]
Then if you want to check if first is a vowel, you can just do:
if first in 'aeuoiy'
Answer to your actual question: do not assign L to an empty list!
If you want to repeat the action of a function, you can just call it again, no need to rewrite the code.

Categories

Resources