how to upper string characters at once? - python

i want to take astring and indeses on that string and to convert these characters on those indexes to upper.
this is what I've tried but it doesn't work. it shows
"list indices must be integers or slices, not list"
test = 'hello there'
l = list(test)
def capital(s, ind):
for i in s:
i = list(i)
i[ind] = i[ind].upper()
print(s)
capital(l,[1,2,5])

It doens't seem correct to iterate over each character of the string. A more correct approach would be to iterate on each index in ind and capitalize those characters.
Anyway this can be one with a one-liner using a list comprehension:
def capital(s, ind):
capitalized = [s[i].upper() if i in ind else s[i] for i in range(len(s))]
return ''.join(capitalized)

People are overcomplicating this in their answers. You shouldn't need to iterate over the string, if you already have a defined list of indexes to capitalize. Here's what you can do, iterating only over the indexes parameter:
def capital(text, indexes):
split_text = list(text)
for i in indexes:
split_text[i] = split_text[i].upper()
return ''.join(split_text)
capitalized = capital('hello there', [1, 2, 5])
print(capitalized)
This would print hELlo there.
A shorter alternative would be using the function enumerate, since you're working with both values and indexes of a sequence (string):
def capital(text, indexes):
return ''.join(c.upper() if i in indexes else c for i,c in enumerate(text))
This would also work perfectly fine.

I think you mixed up the list you pass as a second parameter in your capital function and the list of caracters you have created.
Here is a way to properly write your function :
test = 'hello there'
def capital(s, ind):
for i in ind:
s[i] = s[i].upper()
return(s)
print(capital(list(test),[1,2,5]))

Here is the corrected way to define a function that takes in a list of characters and a list of indexes, and prints out the list with the specified indexes uppercased:
test = 'hello there'
l = list(test)
def capital(s, ind):
for i in ind:
s[i] = s[i].upper()
print(s)
capital(l,[1,2,5])
Output:
['h', 'E', 'L', 'l', 'o', ' ', 't', 'h', 'e', 'r', 'e']
Here is a simpler version that does not require a pre-conversion from a string to a list, it simply takes in a string and a list of indices:
def capital(s, ind):
s = ''.join([c.upper() if i in ind else c for i,c in enumerate(s)])
print(s)
capital('hello world',[1,2,5])
Output:
hELlo world

see fixes in line. you meant to do this this is the right way to to do it.
in your code i[ind] = i[ind].upper(). ind is a list! this is an error. see my code below:
test = 'hello there'
l = list(test)
def capital(s, ind):
for i in range(len(s)): #i is one letter - charachter
if i in ind:
s[i] = s[i].upper() #it expects an integer! you have passed a list
print(s)
capital(l, [1,2,5])
Effictive approach
test = 'hello there'
l = list(test)
def capital(s, ind):
for i in ind: #i is one letter - charachter
s[i] = s[i].upper() #it expects an integer! you have passed a list
print(s)
capital(l, [1,2,5])

Related

How to index, remove and count all instances of an element within a list?

I am new to Python and I am trying to learn something about lists. In this case, my objective is to index, count and remove all instances of an element within a list. The indexing, counting and removing all works fine separately, yet I am struggling to merge it and get the desired results. What am I doing wrong?
def removing(letter,lst):
'''This function should index and remove all entries of a letter within a list, returning the removed items' position within the original list. I then use len() function on the result-list to determine how many items have been indexed/deleted'''
result=[]
offset= -1
list_new = lst.copy()
while True:
try:
offset=list_new.index(letter, offset+1)
except ValueError:
return result
print('Letter not found.')
result.append(offset)
lst.remove(letter)
Now I expected that even without cloning the list, this would do the trick, and the function returns the letters' positions and removes them, but when I define lst and letter, run the function and then say:
print(len(removing(letter,lst)))
It always says 0. Why is that?
EDIT: I have been advised to call the function once and store the result, yet I when I do the following, the result is the same:
c=1
print(lst)
while (c==1):
letter=input('What letter do you want to remove?\n')
if letter in lst:
var=removing(letter,lst)
print(var)
print(str(len(var))+' letters have been removed.')
print(lst)
else:
c-1
Thank you all for your help, my question has been answered. The problem was not in the function but it was me calling the function multiple times without storing the result. Final code looks like this:
lst= list('Nach langem rumprobieren haben nette Menschen mir bei der Vollendung dieser kleinen Übungsaufgabe geholfen.')
def removing(letter,lst):
'This function should remove all entries of a letter within a list'
result=[]
offset= -1
list_new = lst.copy()
while True:
try:
offset=list_new.index(letter, offset+1)
except ValueError:
return result
result.append(offset)
lst.remove(letter)
c=1
print(lst)
while (c==1):
letter=input('What letter do you want to remove?\n')
if letter in lst:
var=removing(letter,lst)
print(var)
print(str(len(var))+' letters have been removed.')
print(lst)
else:
break
Your loop isn't necessary, and will loop infinitely. Try the below
lst = list('abracadabra')
letter = 'a'
var=removing(letter,lst)
print(var) # [0, 3, 5, 7, 10]
print(str(len(var))+' letters have been removed.') # 5 letters have been removed.
print(lst) # ['b', 'r', 'c', 'd', 'b', 'r']
Another way of writing the function in a slightly more pythonic way would be something like
def remove(lst, item):
new_list = []
indices = []
for i, x in enumerate(lst):
if x == item:
indices.append(i)
else:
new_list.append(x)
return new_list, indices
Here is my solution:
import re
def removing(c, s):
'''This function removes all occurences of 'c' in 's' and return a list of the replaced indices'''
indices = [i.span()[0] for i in re.finditer(c, s)]
return s.replace(c, ''), indices
And here is the usage example:
>>> removing('a', 'abracadabra')
('brcdbr', [0, 3, 5, 7, 10])
>>>
>>> removing('a', 'aaaaa')
('', [0, 1, 2, 3, 4])
>>>

How to split a list based on whether the elements were next to each other in the list they came from?

I'm going through Problem 3 of the MIT lead python course, and I have an admittedly long drawn out script that feels like it's getting close. I need to print the longest substring of s in which the letters occur in alphabetical order. I'm able to pull out any characters that are in alphabetical order with regards to the character next to it. What I need to see is:
Input : 'aezcbobobegghakl'
needed output: 'beggh'
my output: ['a', 'e', 'b', 'b', 'b', 'e', 'g', 'g', 'a', 'k']
My code:
s = 'aezcbobobegghakl'
a = 'abcdefghijklmnopqrstuvwxyz'
len_a = len(a)
len_s = len(s)
number_list = []
letter_list = []
for i in range(len(s)):
n = 0
letter = s[i+n]
if letter in a:
number_list.append(a.index(letter))
n += 1
print(number_list)
for i in number_list:
letter_list.append(a[i])
print(letter_list)
index_list = []
for i in range(len(letter_list)):
index_list.append(i)
print(index_list)
first_check = []
for i in range(len(letter_list)-1):
while number_list[i] <= number_list[i+1]:
print(letter_list[i])
first_check.append(letter_list[i])
break
print(first_check)
I know after looking that there are much shorter and completely different ways to solve the problem, but for the sake of my understanding, is it even possible to finish this code to get the output I'm looking for? Or is this just a lost cause rabbit hole I've dug?
I would build a generator to output all the runs of characters such that l[i] >= l[i-1]. Then find the longest of those runs. Something like
def runs(l):
it = iter(l)
try:
run = [next(it)]
except StopIteration:
return
for i in it:
if i >= run[-1]:
run.append(i)
else:
yield run
run = [i]
yield run
def longest_increasing(l):
return ''.join(max(runs(l), key=len))
Edit: Notes on your code
for i in range(len(s)):
n = 0
letter = s[i+n]
if letter in a:
number_list.append(a.index(letter))
n += 1
is getting the "number value" for each letter. You can use the ord function to simplify this
number_list = [ord(c) - 97 for c in s if c.islower()]
You never use index_list, and you never should. Look into the enumerate function.
first_check = []
for i in range(len(letter_list)-1):
while number_list[i] <= number_list[i+1]:
print(letter_list[i])
first_check.append(letter_list[i])
break
this part doesn't make a ton of sense. You break out of the while loop every time, so it's basically an if. You have no way of keeping track of more than one run. You have no mechanism here for comparing runs of characters against one another. I think you might be trying to do something like
max_run = []
for i in range(len(letter_list)-1):
run = []
for j in range(i, len(letter_list)):
run.append(letter_list[j])
if letter_list[j] > letter_list[j+1]:
break
if len(run) > len(max_run):
max_run = run
(Disclaimer: I'm pretty sure the above is off by one but it should be illustrative). The above can be improved in a lot of ways. Note that it loops over the last character as many as len(s) times, making it a n**2 solution. Also, I'm not sure why you need number_list, as strings can be compared directly.
What about a simple recursive approach :
data = 'ezcbobobegghakl'
words=list(data)
string_s=list(map(chr,range(97,123)))
final_=[]
def ok(list_1,list_2):
if not list_1:
return 0
else:
first = list_1[0]
chunks = list_2[list_2.index(first):]
track = []
for j, i in enumerate(list_1):
if i in chunks:
track.append(i)
chunks=list_2[list_2.index(i):]
else:
final_.append(track)
return ok(list_1[j:],list_2)
final_.append(track)
print(ok(words,string_s))
print(max(final_,key=lambda x:len(x)))
output:
['b', 'e', 'g', 'g', 'h']
You can find a list of all substrings of the input string, and then find all the strings that are sorted alphabetically. To determine of a letter is sorted alphabetically, sorted the original string by position in the alphabet, and then see if the final string equals the original string:
from string import ascii_lowercase as l
s = 'aezcbobobegghakl'
substrings = set(filter(lambda x:x, [s[i:b] for i in range(len(s)) for b in range(len(s))]))
final_substring = max([i for i in substrings if i == ''.join(sorted(list(i), key=lambda x:l.index(x)))], key=len)
Output:
'beggh'
This is one way of getting the job done:
s = 'aezcbobobegghakl'
l = list(s)
run = []
allrun = []
element = 'a'
for e in l:
if e >= element:
run.append(e)
element = e
else:
allrun.append(run)
run = [e]
element = e
lengths = [len(e) for e in allrun]
result = ''.join(allrun[lengths.index(max(lengths))])
"run" is basically an uninterrupted run; it keeps growing as you add elements bigger than what is previously seen ("b" is bigger than "a", just string comparison), and resets else.
"allrun" contains all "run"s, which looks like this:
[['a', 'e', 'z'], ['c'], ['b', 'o'], ['b', 'o'], ['b', 'e', 'g', 'g', 'h']]
"result" finally picks the longest "run" in "allrun", and merges it into one string.
Regarding your code:
It is very very inefficient, I would not proceed with it. I would adopt one of the posted solutions.
Your number_list can be written as [a.index(_) for _ in s], one liner.
Your letter_list is actually just list(s), and you are using a loop for that!
Your index_list, what does it even do? It is equivalent to range(len(letter_list)), so what are you aiming with the append in the loop?
Finally, the way you write loops reminds me of matlab. You can just iterate on the elements of a list, no need to iterate on index and fetch the corresponding element in list.

Accumulating lists with letters

I'm trying to right a code that accumulates a list.
The code I've figured out so far does that but I want to make it work with letters e.g.
accumulate("a", "b", "c")
would come out to be a, ab, abc.
def accumulate(L):
theSum = 0
for i in L:
theSum = theSum + i
print(theSum)
return theSum
accumulate([1, 2, 3])
While #WillemVanOnsem has provided you with the method that would work, to shorten your code you can use itertools.accumulate from the standard library:
>>> from itertools import accumulate
>>>
>>> for step in accumulate(['a', 'b', 'c']):
print(step)
a
ab
abc
>>>
You can try this:
import string
l = string.ascii_lowercase
the_list = []
letter = ""
for i in l:
letter += i
the_list.append(letter)
Even better in a function with a generator:
def accumulation():
l = string.ascii_lowercase
letter = ""
for i in l:
letter += i
yield letter
the_letters = list(accumulation())
print(the_letters)
Output:
['a', 'ab', 'abc', 'abcd', 'abcde', 'abcdef', 'abcdefg', 'abcdefgh', 'abcdefghi', 'abcdefghij', 'abcdefghijk', ...]
If you want to let it work with strings, you have to initialize it with an empty string:
def accumulate(*args):
theSum = ''
for i in args:
theSum += i # we can here shorten it to += (kudos to #ChristianDean)
print(theSum)
return theSum
Furthermore if you want to use an arbitrary number of arguments, you should use *args (or *L).
Now of course this will no longer work with numbers. The theSum += i is here short for theSum = theSum + i (since strings are immutable). Note however that this is not always the case: for lists there is a difference for instance.
Now it prints:
>>> accumulate("a", "b", "c")
a
ab
abc
'abc'
The last 'abc' is not a result of a print(..) statement, but it is the return of the accumulate function.

There is something wrong with my Python code involve the replace function

I was creating a function about replacing multiple part of a string with multiple number but for some reason, the output is not what i expected.
from pyprimes import isprime
def prime_replace(x, l = []):
lst = []
string = str(x)
for n in range(10):
for i in l:
string = string.replace(string[i], str(n))
lst.append(int(string))
return lst
print prime_replace(x = 56243, l = [2, 3])
The output of this function is a list [56003, 56113, 56223, 56333, 56444, 56555, 66666, 77777, 88888, 99999] but what i wanted is [56003, 56113, 56223, 56333, 56443, 56553, 56663, 56773, 56883, 56993] Can someone help me with this and tell me what went wrong, thank you.
You're modifying the original string, and replace is replacing "all occurrences"
Here's part of a print out for how it's generating the output you see:
...
string is now 56333
replacing 3 with 3
string is now 56333
replacing 3 with 4
string is now 56444
...
You can see that we successfully got 56333 like you wanted, but then you wanted to replace str[2] (actual value: 3) with str(n) (actual value: 4), which replaced all occurrences of 3
One workaround for this specific scenario is to make a copy of your string:
def prime_replace(x, l = []):
lst = []
string = str(x)
for n in range(10):
newstr = string
for i in l:
newstr = newstr.replace(string[i], str(n))
lst.append(int(newstr))
return lst
print prime_replace(x = 56243, l = [2, 3])
Output:
[56003, 56113, 56223, 56333, 56443, 56553, 56663, 56773, 56883, 56993]
Demo (not recommended)
However, replace may not be the best choice since it will replace all occurrences of the "oldstring" with the "newstring". It looks like what you're really trying to do is to change string at indices in l to be the next value in range(10), we can do this through indexing and appending:
def prime_replace(x, l = []):
lst = []
string = str(x)
for n in range(10):
newstr = string
for i in l:
newstr = newstr[0:i]+str(n)+newstr[i+1:];
lst.append(int(newstr))
return lst
Demo (better)
string.replace(a,b) replaces all instances of a with b. so, '56243'.replace(3,0) evaluates to '56240'. You are trying to replace the values at the indicies in l, so you should replace
string = string.replace(string[i], str(n))
with
string = string[:i] + str(n) + string[i+1:]
The other answer fails on cases where the value at an index to be replaced is repeated elsewhere in the number, i.e. prime_replace(562432,[2,3])
I have also found another solution for it by turning the string into list
from pyprimes import isprime
def prime_replace(x, l):
lst = []
string_lst = list(str(x))
for n in range(10):
for i in l:
string_lst[i] = str(n)
lst.append(int("".join(string_lst)))
return lst
print prime_replace(56243, [2, 3])
Output
[56003, 56113, 56223, 56333, 56443, 56553, 56663, 56773, 56883, 56993]
But thank you very much for your solution.
You really want a mutable data-structure here to simplify your logic. You can get what is essentially a mutable string by using a bytearray. So here is an alternative approach:
In [11]: def prime_replace(x, l=None):
...: if l is None:
...: l = [] # careful with mutable default arguments
...: lst = []
...: string = bytearray(str(x), encoding='ascii')
...: for n in b'0123456789':
...: for i in l:
...: string[i] = n
...: lst.append(int(string))
...: return lst
...:
In [12]: prime_replace(x = 56243, l = [2, 3])
Out[12]: [56003, 56113, 56223, 56333, 56443, 56553, 56663, 56773, 56883, 56993]
Also, be careful with mutable default arguments.
I use a bytearray because I think it simplifies things more. A list also works. But note with bytearray and by iterating directly over the ascii b'012345679' it simplifies everything by a lot, and you don't have to keep converting things back-and-forth between str and int

Convert a list to a string without 'join'

I'm trying to create my own function that converts a list of characters into a string. I'm not allowed to use 'join'. I need to use a loop to do this. I think I have the basis of it right, but I'm not really sure how to implement it into the function properly. I'm new to programming.
Here's the code I'm using:
def to_string(my_list):
# This line will eventually be removed - used for development purposes only.
print("In function to_string()")
# Display letters in a single line
for i in range(len(my_list)):
print(my_list[i], end='')
# Separate current letter from the next letter
if i<(len(my_list))-1:
print(", ", end='')
# Returns the result
return ('List is:', my_list)
That returns the result I want (if the list is ['a', 'b', 'c'] it returns a, b, c). But there's a 'test file' we're meant to use to run the function which contains this code:
print("\nto_string Test")
string = list_function.to_string(str_list1)
print(string)
print(list_function.to_string(empty))
And it gives this result:
to_string Test
In function to_string()
r, i, n, g, i, n, g('List is:', ['r', 'i', 'n', 'g', 'i', 'n', 'g'])
In function to_string()
('List is:', [])
Which seems to indicate that I messed up entirely, something to do with the 'print' function I think. Can anyone please tell me where I'm going wrong?
Your function prints your string to stdout, then returns the list itself unchanged.
Build a string and return that instead of printing:
def to_string(my_list):
result = ''
last = len(my_list) - 1
for pos, elem in enumerate(my_list):
result += str(elem)
if pos != last:
result += ', '
return result
This loops over all elements, keeping a position counter with the enumerate() function; this way it's easy to detect if we are adding the last element to the result.
You could also use reduce function:
aList=['w','o','r','d']
aString=reduce(lambda x,y:x+y,aList)
If you want to emulate the .join() method of strings than you may want to add a delimiter option to your function.
def to_string(my_list, delimiter):
string = str(my_list.pop(0))
while my_list:
string += delimiter + str(my_list.pop(0))
return string
.pop(n) will delete the nth element from the list and return it.
If you want to return the original list as well:
def to_string(my_list, delimiter):
string = ''
if my_list:
string = my_list[0]
for elem in my_list[1:]:
string += delimiter + str(elem)
return my_list, string
The syntax my_list[n] will get the nth element from the list. Note that the elements are numbered from 0, not from 1. The syntax my_list[n:] will return the elements of the list starting from n. Example:
>>> my_list = ['this', 'is', 'a', 'list']
>>> my_list[1:]
['is', 'a', 'list']
Loop over the list elements and add them to your string. (Just a simpler version of the proposed solutions)
def to_string(my_list):
result_string = ''
for element in my_list:
result_string += element
return result_string
To test:
a_list = ['r', 'i', 'n', 'g', 'i', 'n', 'g']
print to_string(a_list) # prints ringing
b_list = []
print to_string(b_list) # returns empty
Maybe a unique way of doing it.
#Python print() has a unique ability
List = ['a','b','c']
print(*List,sep="")
#### Output ####
abc
# In this method I'm trying to using python's print() ability
# and redirecting the print() from standard output to a temporary variable
# and then using it.
from io import StringIO # Python3
import sys
old_stdout = sys.stdout
result = StringIO() #store everything that is sent to the standard output
sys.stdout = result
print(*List, sep = "") #sends to variable result
#or do any fancy stuff here
sys.stdout = old_stdout # Redirect again the std output to screen
result_string = result.getvalue().strip() # strip() because it has \n at the end
print(result_string,type(result_string),len(result_string),sep="\n")
#this actually prints(), and also the result_string variable has that value
#### Output ####
abc
<class 'str'>
3
This will help you indetail. Store standard output on a variable in Python

Categories