Mutating strings in python - python

My brain cannot comprehend why this isn't working. I'm not very experienced and just trying to practice loops.
I'm trying to create a function that takes a string (currently one word) and capitalizes letters at random. With this code python throws a TypeError: list indices must be integers or slices, not strings
Here's what I have:
import random
list = []
def hippycase(string):
for letter in string:
list.append(letter)
for index in list:
if random.randint(1,2) == 1:
list[index] = list[index].upper()
else:
list[index] = list[index].lower()
return list
print(hippycase("pineapple"))
Any ideas or tips? Thanks
EDIT: Since this has been marked as a duplicate as someone thinks is at the following link, I'll try and clear up what is different:
Accessing the index in Python 'for' loops
I'm not trying to actively seek the index, I'm just practicing for loops which coincidentally goes through the index of the iterable sequentially. I also think if a fellow noob coder is searching this might be more helpful.

Here's a slightly improved version of your code
def hippycase(string):
charlist = []
for char in string:
if random.randint(1,2) == 1:
charlist.append(char.upper())
else:
charlist.append(char.lower())
return charlist
Notice that in this version we're looking only at the characters in your string, we don't care about the indices - this helps to reduce confusion.
If I were writing this to actually "hippycase" a string I would probably return "".join(charlist), so the calling function would get back a string (which is what they probably expect)
Also, it is bad practice to overwrite the list reserved word.

The variable "index" that you are using is a letter from the string, because you are iterating over it. To fix this error, use the range() function, which will allow you to access each element in the list by index:
list = []
def hippycase(string):
for letter in string:
list.append(letter)
for index in range(len(list)): #here, we are accessing the elements by index
if random.randint(1,2) == 1:
list[index] = list[index].upper()
else:
list[index] = list[index].lower()
return list
print(hippycase("pineapple"))
Another way is simple list comprehension:
the_string = "pineapple"
print ''.join([i.upper() if random.randint(1, 2) == 1 else i for i in the_string])

Related

Changing(replacing) a value in a list without using range(len())

My purpose is to change the value of the elements 3 and 4 to 4 and 3 and I have written a function that takes a list, first number and second number as arguments:
def pre9(the_list, value_to_replace, the_replacing_value):
for i in the_list:
if i == value_to_replace:
value_to_replace = the_replacing_value
elif i == the_replacing_value:
the_replacing_value = value_to_replace
return the_list
I then assign a test-case to a variabel and then print it:
test_pre9 = pre9([1,2,3,4,5,7,3,4], 3, 4)
print(test_pre9)
The result is: [1,2,3,4,5,7,3,4]
I expect it to be: [1,2,4,3,5,7,4,3]
I have for a long time ago written a code that accoplishes this task:
def uppgift_9():
the_list = [3,5,8,9,4,5]
for i in range(len(the_list)-1):
temp = the_list[3]
the_list[3] = the_list[4]
the_list[4] = temp
return the_list
But I've read in many places that using range(len()) is not "pythonic" and it is possible to do anything without using it.
Does anyone know why my code fails?
You don't actually change the item in the list, try this:
def pre9(the_list, value_to_replace, the_replacing_value):
for i, value in enumerate(the_list):
if value == value_to_replace:
the_list[i] = the_replacing_value
elif value == the_replacing_value:
the_list[i] = value_to_replace
return the_list
Now the list will have the actually items changed to what you wanted it to be. Enumerate() returns the index and value of an item in a list, it's very handy! And indeed, the range(len()) is not very pythonic and is usually used when people jump from other languages like Java, C# etc. Using enumerate() is the correct 'pythonic' way of achieving this.

sub-sum from a list without loops

So i'm studying recursion and have to write some codes using no loops
For a part of my code I want to check if I can sum up a subset of a list to a specific number, and if so return the indexes of those numbers on the list.
For example, if the list is [5,40,20,20,20] and i send it with the number 60, i want my output to be [1,2] since 40+20=60.
In case I can't get to the number, the output should be an empty list.
I started with
def find_sum(num,lst,i,sub_lst_sum,index_lst):
if num == sub_lst_sum:
return index_lst
if i == len(sum): ## finished going over the list without getting to the sum
return []
if sub_lst_sum+lst[i] > num:
return find_sum(num,lst,i+1,sub_lst_sum,index_lst)
return ?..
index_lst = find_sum(60,[5,40,20,20,20],0,0,[])
num is the number i want to sum up to,
lst is the list of numbers
the last return should go over both the option that I count the current number in the list and not counting it.. (otherwise in the example it will take the five and there will be no solution).
I'm not sure how to do this..
Here's a hint. Perhaps the simplest way to go about it is to consider the following inductive reasoning to guide your recursion.
If
index_list = find_sum(num,lst,i+1)
Then
index_list = find_sum(num,lst,i)
That is, if a list of indices can be use to construct a sum num using elements from position i+1 onwards, then it is also a solution when using elements from position i onwards. That much should be clear. The second piece of inductive reasoning is,
If
index_list = find_sum(num-lst[i],lst,i+1)
Then
[i]+index_list = find_sum(num,lst,i)
That is, if a list of indices can be used to return a sum num-lst[i] using elements from position i+1 onwards, then you can use it to build a list of indices whose respective elements sum is num by appending i.
These two bits of inductive reasoning can be translated into two recursive calls to solve the problem. Also the first one I wrote should be used for the second recursive call and not the first (question: why?).
Also you might want to rethink using empty list for the base case where there is no solution. That can work, but your returning as a solution a list that is not a solution. In python I think None would be a the standard idiomatic choice (but you might want to double check that with someone more well-versed in python than me).
Fill in the blanks
def find_sum(num,lst,i):
if num == 0 :
return []
elif i == len(lst) :
return None
else :
ixs = find_sum(???,lst,i+1)
if ixs != None :
return ???
else :
return find_sum(???,lst,i+1)

Function to reverse text characters

I am trying to make a reverse function which takes an input (text) and outputs the reversed version. So "Polar" would print raloP.
def reverse(text):
list = []
text = str(text)
x = len(text) - 1
list.append("T" * x)
for i in text:
list.insert(x, i)
x -= 1
print "".join(list)
reverse("Something")
As others have mentioned, Python already provides a couple of ways to reverse a string. The simple way is to use extended slicing: s[::-1] creates a reversed version of string s. Another way is to use the reversed function: ''.join(reversed(s)). But I guess it can be instructive to try implementing it for yourself.
There are several problems with your code.
Firstly,
list = []
You shouldn't use list as a variable name because that shadows the built-in list type. It won't hurt here, but it makes the code confusing, and if you did try to use list() later on in the function it would raise an exception with a cryptic error message.
text = str(text)
is redundant. text is already a string. str(text) returns the original string object, so it doesn't hurt anything, but it's still pointless.
x = len(text) - 1
list.append("T" * x)
You have an off-by-one error here. You really want to fill the list with as many items as are in the original string, this is short by one. Also, this code appends the string as a single item to the list, not as x separate items of one char each.
list.insert(x, i)
The .insert method inserts new items into a list, the subsequent items after the insertion point get moved up to make room. We don't want that, we just want to overwrite the current item at the x position, and we can do that by indexing.
When your code doesn't behave the way you expect it to, it's a Good Idea to add print statements at strategic places to make sure that variables have the value that they're supposed to have. That makes it much easier to find where things are going wrong.
Anyway, here's a repaired version of your code.
def reverse(text):
lst = []
x = len(text)
lst.extend("T" * x)
for i in text:
x -= 1
lst[x] = i
print "".join(lst)
reverse("Something")
output
gnihtemoS
Here's an alternative approach, showing how to do it with .insert:
def reverse(text):
lst = []
for i in text:
lst.insert(0, i)
print "".join(lst)
Finally, instead of using a list we could use string concatenation. However, this approach is less efficient, especially with huge strings, but in modern versions of Python it's not as inefficient as it once was, as the str type has been optimised to handle this fairly common operation.
def reverse(text):
s = ''
for i in text:
s = i + s
print s
BTW, you really should be learning Python 3, Python 2 reaches its official End Of Life in 2020.
You can try :
def reverse(text):
return text[::-1]
print(reverse("Something")) # python 3
print reverse("Something") # python 2
Easier way to do so:
def reverse(text):
rev = ""
i = len(text) - 1
while i > -1:
rev += text[i]
i = i - 1
return rev
print(reverse("Something"))
result: gnihtemoS
You could simply do
print "something"[::-1]

Returning position of specific symbol in list of lists

For this function I'm writing I want to return the position of a specific character that is closest to the top left of the list of lists. It'd be great to accomplish this in the most basic way without importing modules. Here is the code I have so far then I will explain more about what I'm trying to do
def find_position(symbol,lst):
# Sample List: [['.','M','M','G','G'],
# ['.','.','.','.','h'],
# ['B','B','B','.','h']]
#
for sublist in lst:
for symbol in sublist:
if symbol == True:
lst.find(symbol)
return symbol
else:
return None
So if the function was instructed to find '.' then it should return (0,0) since it is in the first position of the first list. If the function was told to find 'h' then it should return (1,4) since it is in the 4th position (python starts from 0) of the second list. My current code doesn't look for the character closest to the top left as I'm not sure how to program that. Thanks in advance for any help I receive.
A function that iterates through all elements until it finds the character. As soon as it finds it, it returns the position. To find the psotion you can use the enumerate fucntion which returns a tuple containing a count (from start which defaults to 0) and the values obtained from iterating over sequence
def find_position(symbol,lst):
for index, my_list in enumerate(s):
for i,item in enumerate(my_list):
if symbol == item:
return "{},{}".format(index,i)
return "Not found"
s = [['.','M','M','G','G'],
['.','.','.','.','h'],
['B','B','B','.','h']]
a = find_position("h",s)
Daniel's way is a bit faster in time execution but this also works for comparison:
def find_pos(listname, symbol):
for i in range(len(listname)):
for j in listname[i]:
if j == symbol:
return i ,listname[i].index(j)

my python code is not working.....i want to find if the entered list contains duplicate items

I want to use this function to find duplicate items in my list, but this code is not working:
p = "enter a list\n"
t = raw_input(p)
def has_duplicate(t):
o = sorted(t)
i = 0
while i < len(o):
if o[i] == o[i + 1]:
print "the list has duplicates"
elif o[i] != o[i+1]:
i += 1
if i >= len(o):
print "the list has no duplicate"
It gives me an error saying has_duplicates not defined.
As #mgilson commented, your issue is you are calling the function incorrectly (has_duplicates vs has_duplicate) however...
The most straight forward way to do this is using a set and comparing len.
def has_duplicates(t):
return len(set(t)) != len(t)
If you take an iterable and wrap it in a set you will end up with only unique items. If the length of the set is the same as your original iterable then you have no duplicates. If the length is different (will always be equal to or smaller) then you have duplicates which were removed when converting to a set type.
First thing is you do list_name.sort().
Other easy way to find duplicates is
len(your_list)!=len(set(your_list))
you might be calling function has_duplicates but you have defined has_duplicate function.
try to call has_duplicate

Categories

Resources