Python 3.xx - Deleting consecutive numbers/letters from a string - string

I actually need help evaluating what is going on with the code which I wrote.
It is meant to function like this:
input: remove_duple('WubbaLubbaDubDub')
output: 'WubaLubaDubDub'
another example:
input: remove_duple('aabbccdd')
output: 'abcd'
I am still a beginner and I would like to know both what is wrong with my code and an easier way to do it. (There are some lines in the code which were part of my efforts to visualize what was happening and debug it)
def remove_duple(string):
to_test = list(string)
print (to_test)
icount = 0
dcount = icount + 1
for char in to_test:
if to_test[icount] == to_test[dcount]:
del to_test[dcount]
print ('duplicate deleted')
print (to_test)
icount += 1
elif to_test[icount] != to_test[dcount]:
print ('no duplicated deleted')
print (to_test)
icount += 1
print ("".join(to_test))

Don't modify a list (e.g. del to_test[dcount]) that you are iterating over. Your iterator will get screwed up. The appropriate way to deal with this would be to create a new list with only the values you want.
A fix for your code could look like:
In []:
def remove_duple(s):
new_list = []
for i in range(len(s)-1): # one less than length to avoid IndexError
if s[i] != s[i+1]:
new_list.append(s[i])
if s: # handle passing in an empty string
new_list.append(s[-1]) # need to add the last character
return "".join(new_list) # return it (print it outside the function)
remove_duple('WubbaLubbaDubDub')
Out[]:
WubaLubaDubDub
As you are looking to step through the string, sliding 2 characters at a time, you can do that simply by ziping the string with itself shifted one, and adding the first character if the 2 characters are not equal, e.g.:
In []:
import itertools as it
def remove_duple(s):
return ''.join(x for x, y in it.zip_longest(s, s[1:]) if x != y)
remove_duple('WubbaLubbaDubDub')
Out[]:
'WubaLubaDubDub'
In []:
remove_duple('aabbccdd')
Out[]:
'abcd'
Note: you need itertools.zip_longest() or you will drop the last character. The default fillvalue of None is fine for a string.

Related

Incorporate a while loop in a function in Python

Very new to any kind of coding. I would like to write a function that will return the elements of a numeric list, up to the first even number. For example, if the list is [1,5,7,8,9] it will return [1,5,7]
I know the below is not correct, but I am having trouble passing the list into the while loop.
def iter_up_to_even(num_lst):
i=0
new_lst=[]
while i < len(num_lst):
if i%2!=0:
new_lst.append(num_lst)
i=i+1
if i %2==0:
break
return new_lst
Looks like you might have some indentation issues. Try this solution:
def iter_up_to_even(num_list):
to_return = []
current_index = 0 if len(num_list) > 0 else len(num_list)
while current_index < len(num_list):
if num_list[current_index] % 2 == 1:
to_return.append(num_list[current_index])
else:
break
current_index += 1
return to_return
Explanation
We start with an empty list to_return, which we will return at the end of our function. Next, we iterate through each item in the input list num_list. If the input list num_list is empty to begin with, we don't even enter the while loop (see Line 3). If the item is odd, we append it to our to_return list. If it's even, we break from our loop and return to_return.
In addition, you should compare values in the list (e.g. num_list[i]), rather than the current index in the list (e.g. i).

Look ahead in a for loop iterating through a string?

I have a simple for loop iterating through a user input string. If the it encounters a certain value, I want to be able to look ahead at the next value in order to determine what to do next. What is the best way to accomplish this? For example in my code below, if it encounters a "1" in the string, it should look at the next character in the string. If it is also a 1, print 1. Otherwise do nothing.
UserInput = input("Enter calculator expression:")
for x in UserInput:
...
...
if x == 1:
# if the next value in the string is 1:
# print 1
# else:
# do nothing
Use range and len in the loop to get position address
UserInput = input("Enter calculator expression")
for i in range(len(UserInput)-1):
if x[i]=='1':
if x[i+1]=='1':
print "something"
else:
pass
You can zip a string with itself, but offset with a slice.
>>> from itertools import zip_longest
>>> the_input = 'foobar' # example
>>> the_input[1:] # slice off the first character
'oobar'
>>> for c, lookahead in zip_longest(the_input, the_input[1:]):
... print(c, lookahead)
...
f o
o o
o b
b a
a r
r None
This is more Pythonic than using an index like you would in a language like C.
Zipping pairs things elementwise, like the teeth of a zipper.
You can user enumerate() function.
something like this,
#!/user/bin/python3
for i,x in enumerate(UserInput):
if x=='1':
if UserInput[i+1] == '1':
print('1')
Firstly, python convention is snake-case (user_input instead)
code below is my solution
from itertools import islice
def window(seq, n=2):
it = iter(seq)
result = tuple(islice(it, n))
if len(result) == n:
yield result
for elem in it:
result = result[1:] + (elem,)
yield result
pair = list(window(user_input))
comparison_list = ["1"]
result = [x for x,y in pair if x in comparison_list and x == y]
You don't need to look ahead. At least it is not what we usually do when we tackle this kind of problem. Instead, you should look backward - by storing the information. The following example stores the information in a variable state and you can decide the next action in the subsequent iteration.
UserInput = input("Enter calculator expression:")
state = '0'
for x in UserInput:
if x == '1':
if state == '1':
print('1')
else:
state = '1'
else:
state = '0'
A different (probably more pythonic) way of doing this with the zip function:
for char, next_char in zip(UserInput, UserInput[1:]):
if char == "1" and char == next_char:
print(1)
prev_char = None
for char in input("Enter calculator expression:"):
pass # Here you can check the current character and the previous character
if 1 == prev_char and 1 == char:
print(1)
prev_char = char

why it show me this in result (list index out of range)?

Write a function called stop_at_z that iterates through a list of strings. Using a while loop, append each string to a new list until the string that appears is “z”. The function should return the new list.
def stop_at_z(str):
d = 0
x=[]
str1 = list(str)
while True :
if str1[d] != 'Z' :
x.append(str1[d])
d+=1
if str1[d] == 'Z' :
break
return x
Using a while loop, append each string to a new list until the string that appears is “z”. The function should return the new list.
You're getting this error because d keeps increasing infinitely if there is no uppercase 'Z' in the string. Instead, you should only stay in the while loop while the full length of the input string has not been reached:
def stop_at_z(inputstr):
d = 0
x=[]
str1 = list(inputstr)
while d<len(inputstr) :
if str1[d] == 'z' :
break
else:
x.append(str1[d])
d+=1
return x
Note that you can achieve the same thing using takewhile() from the itertools module:
from itertools import takewhile
def stop_at_z(inputstr):
return list(takewhile(lambda i: i != 'z', inputstr))
print(stop_at_z("hello wzrld"))
Output:
['h', 'e', 'l', 'l', 'o', ' ', 'w']
Is the the way you are doing it, searching for “z” is case-sensitive, try something like:
If str1[d].strip().lower() == “z”
It strips off leading and trailing white space and then converts the str1 element to lower case (both of these simply return the modified string, so the original is unchanged) and compares it to a lower case z
What if the string 'z' is never in the list?
Then it keeps on increasing the index and eventually runs into an error.
Just restricting the loop to the length of the list should help.
def stop_at_z(str):
d = 0
x=[]
str1 = list(str)
for d in range(0,len(str1)) :
print(d)
if str1[d] != 'Z' :
x.append(str1[d])
else:
break
return x
Basically, we needed to have a list that could have all the characters until we get "z". One way we could do that is we first convert the string into a list and iterate that list and add every character to a new list ls until we get "z". But the problem is we may get a string that doesn't have "z" so we need to iterate till the length of that list. I hope it is clear.
def stop_at_z(s):
ls = []
idx = 0
x = list(s)
while idx<len(x):
if x[idx]=="z":
break
ls.append(x[idx])
idx+=1
return ls
It's my first time posting here, but I use this while loop:
def stop_at_z(input_list):
print (input_list)
output_list=[]
index=0
while index< len(input_list):
if input_list[index] != "z":
output_list.append(input_list[index])
index+=1
else:
break
return output_list

How to count number of substrings in python, if substrings overlap?

The count() function returns the number of times a substring occurs in a string, but it fails in case of overlapping strings.
Let's say my input is:
^_^_^-_-
I want to find how many times ^_^ occurs in the string.
mystr=input()
happy=mystr.count('^_^')
sad=mystr.count('-_-')
print(happy)
print(sad)
Output is:
1
1
I am expecting:
2
1
How can I achieve the desired result?
New Version
You can solve this problem without writing any explicit loops using regex. As #abhijith-pk's answer cleverly suggests, you can search for the first character only, with the remainder being placed in a positive lookahead, which will allow you to make the match with overlaps:
def count_overlapping(string, pattern):
regex = '{}(?={})'.format(re.escape(pattern[:1]), re.escape(pattern[1:]))
# Consume iterator, get count with minimal memory usage
return sum(1 for _ in re.finditer(regex, string))
[IDEOne Link]
Using [:1] and [1:] for the indices allows the function to handle the empty string without special processing, while using [0] and [1:] for the indices would not.
Old Version
You can always write your own routine using the fact that str.find allows you to specify a starting index. This routine will not be very efficient, but it should work:
def count_overlapping(string, pattern):
count = 0
start = -1
while True:
start = string.find(pattern, start + 1)
if start < 0:
return count
count += 1
[IDEOne Link]
Usage
Both versions return identical results. A sample usage would be:
>>> mystr = '^_^_^-_-'
>>> count_overlapping(mystr, '^_^')
2
>>> count_overlapping(mystr, '-_-')
1
>>> count_overlapping(mystr, '')
9
>>> count_overlapping(mystr, 'x')
0
Notice that the empty string is found len(mystr) + 1 times. I consider this to be intuitively correct because it is effectively between and around every character.
you can use regex for a quick and dirty solution :
import re
mystr='^_^_^-_-'
print(len(re.findall('\^(?=_\^)',mystr)))
You need something like this
def count_substr(string,substr):
n=len(substr)
count=0
for i in range(len(string)-len(substr)+1):
if(string[i:i+len(substr)] == substr):
count+=1
return count
mystr=input()
print(count_substr(mystr,'121'))
Input: 12121990
Output: 2

Index out of range - Python

I was programming at CodeWars using Kata, when i got this error:
Traceback:
in
in title_case
IndexError: list index out of range
Here is my code:
def title_case(title, minor_words=1):
string = title.split()
outList = []
if minor_words != 1:
split = minor_words.split()
minor = [x.lower() for x in split]
out = ""
for i in range(0, len(string)):
word = ""
for j in range(0,len(string[i])):
elem = ""
elem += string[i][j]
if j == 0:
word += elem.upper()
else:
word += elem.lower()
if i != len(string)-1:
outList.append(word+" ")
else:
outList.append(word)
list = [x.lower() for x in outList]
print ((list[0]))#Just for debug
if minor_words != 1:
for i in range(0, len(outList)):
if (list[i] in minor):
print("OI")#Just for debug
out += list[i]
else:
out += outList[i]
return out
Well, this happened when trying to execute the code, of course!
One way to initialize this function would be:
title_case('a clash of KINGS', 'a an the of')
Well the 0 elemeny exists, but it says it doesn't, I don't know why, because when I write "print(list)" it shows me the elements of list, in this case, "['a', 'clash', 'of', 'kings']".
What can I do?
Okay, so based on reading this code I think the result you desire from:
title_case('a clash of KINGS', 'a an the of') is:
A Clash of Kings
So it looks like you are stepping through a lot of hoops trying to get there. While I was going through the code it took me a while to see what was actually happening. I also took the liberty to make your variables more consistently named. Rather than mixing caseLetter and case_letter randomly I made it consistent. I also made your loops easier to read. Also for the minorWords argument. Might as well have it passed as a list rather than converting it to a list inside the function. Anyway, I hope this is of help.
def titleCase(title, minorWords=[]):
titleList = [x.lower() for x in title.split()]
outList = []
for Word in titleList:
if Word not in minorWords:
Word = Word.capitalize()
outList.append(Word)
return " ".join(outList)
TitleCased = titleCase("a clash of KINGS", ["an", "the", "of"])
print (TitleCased)
Which outputs A Clash of Kings, which I believe, based on your question and how I understood your code is what you wanted to achieve? Or if you include a in your minorWords, it would be:
a Clash of Kings
Regardless, hope this answers your question!

Resources