Not able to remove characters from a string in Python - python

I am trying to loop through a string x that represents the alphabet and at the same time compare those values with a list that contains some specific letters.
If there is a match in both the list and the string x, it should remove the specific character from the string x. It is a very simple and straightforward piece of code. I've followed the .replace method to the T. However, when I ran the code, the string x still shows up in its original state.
Here is my working code:
lettersGuessed = ['e', 'i', 'k', 'p', 'r', 's']
x = 'abcdefghijklmnopqrstuvwxyz'
for i in range(len(x)):
if x[i] in lettersGuessed:
x.replace(x[i],'')
print x "Available Letters"

Try the following
x = x.replace(x[i], '')
You're not reassigning the changed value back to the original string.

Simple mistake.
x = x.replace(x[i],'')

You can use join and a generator expression:
print("Available Letters","".join(ch if ch not in lettersGuessed else "" for ch in x ))
Using a loop, just iterate over the characters in lettersGuessed and update x each time:
for ch in lettersGuessed:
x = x.replace(ch,'') # assign the updated string to x
print("Available Letters",x)
Or iterating over x is the same logic:
for ch in x:
if ch in lettersGuessed:
x = x.replace(ch,'')
strings are immutable so you cannot change the string in place. You need to reassign x to the new string created with x.replace(ch,'')
In [1]: x = 'abcdefghijklmnopqrstuvwxyz'
In [2]: id(x)
Out[2]: 139933694754864
In [3]: id(x.replace("a","foo")) # creates a new object
Out[3]: 139933684264296
In [7]: x
Out[7]: 'abcdefghijklmnopqrstuvwxyz' # no change
In [8]: id(x)
Out[8]: 139933694754864 # still the same object

You could use python sets to achieve this :
a = ['a','b','d']
b = "abcdefgh"
print ''.join(sorted(list(set(b) - set(a))))
output:
cefgh Available letters
Or use list comprehensions to achieve this :
a = ['a','b','d']
b = "abcdefgh"
print ''.join([x for x in b if x not in a])

Related

For statement not replacing based on char position, replacing entire characters [duplicate]

What is the easiest way in Python to replace a character in a string?
For example:
text = "abcdefg";
text[1] = "Z";
^
Don't modify strings.
Work with them as lists; turn them into strings only when needed.
>>> s = list("Hello zorld")
>>> s
['H', 'e', 'l', 'l', 'o', ' ', 'z', 'o', 'r', 'l', 'd']
>>> s[6] = 'W'
>>> s
['H', 'e', 'l', 'l', 'o', ' ', 'W', 'o', 'r', 'l', 'd']
>>> "".join(s)
'Hello World'
Python strings are immutable (i.e. they can't be modified). There are a lot of reasons for this. Use lists until you have no choice, only then turn them into strings.
Fastest method?
There are three ways. For the speed seekers I recommend 'Method 2'
Method 1
Given by this answer
text = 'abcdefg'
new = list(text)
new[6] = 'W'
''.join(new)
Which is pretty slow compared to 'Method 2'
timeit.timeit("text = 'abcdefg'; s = list(text); s[6] = 'W'; ''.join(s)", number=1000000)
1.0411581993103027
Method 2 (FAST METHOD)
Given by this answer
text = 'abcdefg'
text = text[:1] + 'Z' + text[2:]
Which is much faster:
timeit.timeit("text = 'abcdefg'; text = text[:1] + 'Z' + text[2:]", number=1000000)
0.34651994705200195
Method 3:
Byte array:
timeit.timeit("text = 'abcdefg'; s = bytearray(text); s[1] = 'Z'; str(s)", number=1000000)
1.0387420654296875
new = text[:1] + 'Z' + text[2:]
Python strings are immutable, you change them by making a copy.
The easiest way to do what you want is probably:
text = "Z" + text[1:]
The text[1:] returns the string in text from position 1 to the end, positions count from 0 so '1' is the second character.
edit:
You can use the same string slicing technique for any part of the string
text = text[:1] + "Z" + text[2:]
Or if the letter only appears once you can use the search and replace technique suggested
below
Starting with python 2.6 and python 3 you can use bytearrays which are mutable (can be changed element-wise unlike strings):
s = "abcdefg"
b_s = bytearray(s)
b_s[1] = "Z"
s = str(b_s)
print s
aZcdefg
edit: Changed str to s
edit2: As Two-Bit Alchemist mentioned in the comments, this code does not work with unicode.
Strings are immutable in Python, which means you cannot change the existing string.
But if you want to change any character in it, you could create a new string out it as follows,
def replace(s, position, character):
return s[:position] + character + s[position+1:]
replace('King', 1, 'o')
// result: Kong
Note: If you give the position value greater than the length of the string, it will append the character at the end.
replace('Dog', 10, 's')
// result: Dogs
This code is not mine. I couldn't recall the site form where, I took it. Interestingly, you can use this to replace one character or more with one or more charectors.
Though this reply is very late, novices like me (anytime) might find it useful.
Change Text function.
mytext = 'Hello Zorld'
# change all Z(s) to "W"
while "Z" in mytext:
# replace "Z" to "W"
mytext = mytext.replace('Z', 'W')
print(mytext)
Like other people have said, generally Python strings are supposed to be immutable.
However, if you are using CPython, the implementation at python.org, it is possible to use ctypes to modify the string structure in memory.
Here is an example where I use the technique to clear a string.
Mark data as sensitive in python
I mention this for the sake of completeness, and this should be your last resort as it is hackish.
I like f-strings:
text = f'{text[:1]}Z{text[2:]}'
In my machine this method is 10% faster than the "fast method" of using + to concatenate strings:
>>> timeit.timeit("text = 'abcdefg'; text = text[:1] + 'Z' + text[2:]", number=1000000)
1.1691178000000093
>>> timeit.timeit("text = 'abcdefg'; text = f'{text[:1]}Z{text[2:]}'", number =1000000)
0.9047831999999971
>>>
Actually, with strings, you can do something like this:
oldStr = 'Hello World!'
newStr = ''
for i in oldStr:
if 'a' < i < 'z':
newStr += chr(ord(i)-32)
else:
newStr += i
print(newStr)
'HELLO WORLD!'
Basically, I'm "adding"+"strings" together into a new string :).
To replace a character in a string
You can use either of the method:
Method 1
In general,
string = f'{string[:index]}{replacing_character}{string[index+1:]}'
Here
text = f'{text[:1]}Z{text[2:]}'
Method 2
In general,
string = string[:index] + replacing_character + string[index+1:]
Here,
text = text[:1] + 'Z' + text[2:]
if your world is 100% ascii/utf-8(a lot of use cases fit in that box):
b = bytearray(s, 'utf-8')
# process - e.g., lowercasing:
# b[0] = b[i+1] - 32
s = str(b, 'utf-8')
python 3.7.3
I would like to add another way of changing a character in a string.
>>> text = '~~~~~~~~~~~'
>>> text = text[:1] + (text[1:].replace(text[0], '+', 1))
'~+~~~~~~~~~'
How faster it is when compared to turning the string into list and replacing the ith value then joining again?.
List approach
>>> timeit.timeit("text = '~~~~~~~~~~~'; s = list(text); s[1] = '+'; ''.join(s)", number=1000000)
0.8268570480013295
My solution
>>> timeit.timeit("text = '~~~~~~~~~~~'; text=text[:1] + (text[1:].replace(text[0], '+', 1))", number=1000000)
0.588400217000526
A solution combining find and replace methods in a single line if statement could be:
```python
my_var = "stackoverflaw"
my_new_var = my_var.replace('a', 'o', 1) if my_var.find('s') != -1 else my_var
print(f"my_var = {my_var}") # my_var = stackoverflaw
print(f"my_new_var = {my_new_var}") # my_new_var = stackoverflow
```
try this :
old_string = "mba"
string_list = list(old_string)
string_list[2] = "e"
//Replace 3rd element
new_string = "".join(string_list)
print(new_string)

How to do slicing in strings in python?

I am trying to do slicing in string "abcdeeefghij", here I want the slicing in such a way that whatever input I use, i divide the output in the format of a list (such that in one list element no alphabets repeat).
In this case [abcde,e,efghij].
Another example is if input is "aaabcdefghiii". Here the expected output is [a,a,acbdefghi,i,i].
Also amongst the list if I want to find the highest len character i tried the below logic:
max_str = max(len(sub_strings[0]),len(sub_strings[1]),len(sub_strings[2]))
print(max_str) #output - 6
which will yield 6 as the output, but i presume this logic is not a generic one: Can someone suggest a generic logic to print the length of the maximum string.
Here is how:
s = "abcdeeefghij"
l = ['']
for c in s: # For character in s
if c in l[-1]: # If the character is already in the last string in l
l.append('') # Add a new string to l
l[-1] += c # Add the character to either the last string, either new, or old
print(l)
Output:
['abcde', 'e', 'efghij']
Use a regular expression:
import re
rx = re.compile(r'(\w)\1+')
strings = ['abcdeeefghij', 'aaabcdefghiii']
lst = [[part for part in rx.split(item) if part] for item in strings]
print(lst)
Which yields
[['abcd', 'e', 'fghij'], ['a', 'bcdefgh', 'i']]
You would loop over the characters in the input and start a new string if there is an existing match, otherwise join them onto the last string in the output list.
input_ = "aaabcdefghiii"
output = []
for char in input_:
if not output or char in output[-1]:
output.append("")
output[-1] += char
print(output)
To avoid repetition of alphabet within a list element repeat, you can greedily track what are the words that are already in the current list. Append the word to your answer once you detected a repeating alphabet.
from collections import defaultdict
s = input()
ans = []
d = defaultdict(int)
cur = ""
for i in s:
if d[i]:
ans.append(cur)
cur = i # start again since there is repeatition
d = defaultdict(int)
d[i] = 1
else:
cur += i #append to cur since no repetition yet
d[i] = 1
if cur: # handlign the last part
ans.append(cur)
print(ans)
An input of aaabcdefghiii produces ['a', 'a', 'abcdefghi', 'i', 'i'] as expected.

How do i remove a string from a list if it DOES NOT contain certain characters in Python

I am working on a list filter. This is as far as I've gone. I would like to remove every string that doesn't contain H, L OR C. So far this is my attemp
input_list = input("Enter The Results(leave a space after each one):").split(' ')
for i in input_list:
if 'H'not in i or 'L' not in i or 'C' not in i:
Use this pythonic code
input_list = input("Enter The Results(leave a space after each one):").split(' ') # this is the input source
after_removed = [a for a in input_list if ('H' not in a and 'L' not in a and 'C' not in a)] # this is the after removed 'H', 'L', and 'C' from the input_list
Using list comprehension, you can make python easier and faster
If you don't believe, just try it for yourself :D
For clarity, you can use a function
def contains_invalid_character(my_string):
return 'H' in my_string or 'L' in my_string or 'C' in my_string
# To be more pythonic, you can use the following
# return next((True for letter in ("H", "L", "C") if letter in my_string), False)
results = []
for i in input_list:
if not contains_invalid_character(i):
results.append(i)
# Or to be more pythonic
# results = [i for i in input_list if not contains_invalid_character(i)]

Python: append/ extend method

Can someone explain me why after the for loop the list res is ['m']?
string = 'spam'
for x in string:
res =[]
res.extend(x)
print(res)
I expected the output to be res = ['s', 'p', 'a', 'm']
You are replacing the list object each step of your loop. The statement res = [] creates a new, empty list object, then adds a single letter to that list.
Without the loop, this is what you are doing:
>>> x = 's'
>>> res = []
>>> res.extend(x)
>>> res
['s']
>>> x = 'p'
>>> res = []
>>> res.extend(x)
['p']
>>> x = 'a'
>>> res = []
>>> res.extend(x)
>>> res
['a']
>>> res = []
>>> x = 'm'
>>> res.extend(x)
>>> res
['m']
Create the list outside of the loop, once:
string = 'spam'
res = []
for x in string:
res.extend(x)
print(res)
Now you don't keep replacing the list object with a new one each iteration of the for loop.
Again, removing the loop and doing the steps manually, now we have:
>>> res = []
>>> x = 's'
>>> res.extend(x)
>>> res
['s']
>>> x = 'p'
>>> res.extend(x)
>>> res
['s', 'p']
>>> x = 'a'
>>> res.extend(x)
>>> res
['s', 'p', 'a']
>>> x = 'm'
>>> res.extend(x)
>>> res
['s', 'p', 'a', 'm']
Not that you should be using res.extend() here; it only works because individual letters in string assigned to x are each also strings and even single-letter strings are still sequences. What you are really doing with res.extend(x) is the equivalent of for element in x: res.append(element), but x will always have just one element.
So this would work too:
string = 'spam'
res = []
for x in string:
res.append(x)
print(res)
or just extend res with the whole string value:
string = 'spam'
res = []
res.extend(string)
print(res)
or, if you just wanted a list of all the characters of a string, just use the list() function:
string = 'spam'
res = list(string)
print(res)
list() does exactly what you wanted to do with your loop: create an empty list, loop over the input, and add each element to the new list, which is then returned:
>>> string = 'spam'
>>> list(string)
['s', 'p', 'a', 'm']
You are resetting res every time inside the loop. You need to use this-
string = ‘spam’
res =[]
for x in string:
res.extend(x)
print(res)
You'll never get that output because for every iteration of the loop, you are setting res = [] and therefore only the last iteration will work by extending the blank list with 'm'.
The fixed code looks like this:
string = 'spam'
res = []
for x in string:
res.extend(x)
print(res)
Another note is that you probably should use .append in this case. .extend is for appending an entire iterable but since you are only adding one element at a time it isn't necessary. Check here for a good explanation.
Also a last note here is that you'll want to be careful with editing python code outside of plain text or code editors. You're using some leading and trailing apostrophes ‘’ instead of regular '' which will cause you trouble at some point.
You are always re-initializing the res list in the for-loop, that is why in the last iteration of the loop the list is initialized to [] an empty list and the last letter is added to it.
string = 'spam'
res =[]
for x in string:
res.extend(x)
print(res)
or to make it simple, use the list builtin which takes an iterable like a string and converts it into an list object:
>>> list('spam')
['s', 'p', 'a', 'm']
I think this is simplest way:
string = 'spam'
res = list(string)

Python Function to return a list of common letters in first and last names

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():

Categories

Resources