Look ahead in a for loop iterating through a string? - python-3.x

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

Related

how to add characters from array into one string python

I'm trying to change characters from x into upper or lower character depending whether they are in r or c. And the problem is that i can't get all the changed characters into one string.
import unittest
def fun_exercise_6(x):
y = []
r = 'abcdefghijkl'
c = 'mnopqrstuvwxz'
for i in range(len(x)):
if(x[i] in r):
y += x[i].lower()
elif(x[i] in c):
y += x[i].upper()
return y
class TestAssignment1(unittest.TestCase):
def test1_exercise_6(self):
self.assertTrue(fun_exercise_6("osso") == "OSSO")
def test2_exercise_6(self):
self.assertTrue(fun_exercise_6("goat") == "gOaT")
def test3_exercise_6(self):
self.assertTrue(fun_exercise_6("bag") == "bag")
def test4_exercise_6(self):
self.assertTrue(fun_exercise_6("boat") == "bOaT" )
if __name__ == '__main__':
unittest.main()
Using a list as you are using is probably the best approach while you are figuring out whether or not each character should be uppered or lowered. You can join your list using str's join method. In your case, you could have your return statement look like this:
return ''.join(y)
What this would do is join a collection of strings (your individual characters into one new string using the string you join on ('').
For example, ''.join(['a', 'b', 'c']) will turn into 'abc'
This is a much better solution than making y a string as strings are immutable data types. If you make y a string when you are constructing it, you would have to redefine and reallocate the ENTIRE string each time you appended a character. Using a list, as you are doing, and joining it at the end would allow you to accumulate the characters and then join them all at once, which is comparatively very efficient.
If you define y as an empty string y = "" instead of an empty list you will get y as one string. Since when you declare y = [] and add an item to the list, you add a string to a list of string not a character to a string.
You can't compare a list and a string.
"abc" == ["a", "b", "c'] # False
The initial value of y in the fun_exercise_6 function must be ""

How to compare character frequency and return the most occurring character?

I am trying to build a function which returns the most occurred character in a given string and it's working pretty nicely, but how do I return None if the characters have same frequency?
Like for input: 'abac'
Expected output is: 'a'
and for input: 'abab'
Expected output is: None
I have tried using a dictionary to store character frequency and then returning the element with largest value.
def most_occuring_char(str1):
count = {}
max = 0
c = ''
for char in str1:
if char in count.keys():
count[char]+=1
else:
count[char] = 1
for char in str1:
if max < count[char]:
max = count[char]
c = char
return c
I don't know how to check whether the count dictionary elements have same frequency.
You can do that counting with the dict using collections.Counter.
You basically only have to add a check to see if the maximum count is unique (if so, return the char with maximum number of occurrences) or not (if so, return None):
from collections import Counter
def most_occurring_char(string):
counter = Counter(string)
max_char_count = max(counter.values())
is_unique = len([char_count for char_count in counter.values() if char_count == max_char_count]) == 1
if is_unique:
char = [char for char, count in counter.items() if count == max_char_count][0]
return char
return None
# Tests
assert most_occurring_char('abac') == 'a'
assert most_occurring_char('abab') is None
Once you have a dictionary containing the counts of every character (after your first for loop), you can inspect this to determine whether certain counts are the same or not.
If you wish to return None only when all the character counts are the same, you could extract the values (i.e. the character counts) from your dictionary, sort them so they are in numerical order, and compare the first and last values. Since they are sorted, if the first and last values are the same, so are all the intervening values. This can be done using the following code:
count_values = sorted(count.values())
if count_values[0] == count_values[-1]: return None
If you wish to return None whenever there is no single most frequent character, you could instead compare the last value of the sorted list to the second last. If these are equal, there are two or more characters that occur most frequently. The code for this is very similar to the code above.
count_values = sorted(count.values())
if count_values[-1] == count_values[-2]: return None
Another possibility:
def most_occuring_char(s):
from collections import Counter
d = Counter(s)
k = sorted(d, key=lambda x:d[x], reverse=True)
if len(k) == 1: return k[0]
return None if len(k) == 0 or d[k[0]] == d[k[1]] else k[0]
#Test
print(most_occuring_char('abac')) #a
print(most_occuring_char('abab')) #None (same frequencies)
print(most_occuring_char('x')) #x
print(most_occuring_char('abcccba')) #c
print(most_occuring_char('')) #None (empty string)

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

Python 3.xx - Deleting consecutive numbers/letters from a 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.

int object is not iterable?

I was attempting to create a program that would take a user input which would be a string of numbers and print out how many times each number occurred. However, I receive a TypeError stating that the int object is not iterable? How would I fix this and why is it happening? Thank you.
def main():
count = {}
user_input = input("Enter numbers separated by spaces: ")
for number in user_input.split():
if number in count:
count[number] = count[number] + 1
else:
count[number] = 1
print(count)
for k,v in count.values():
if v == 1:
print(k,"occurs one time")
else:
print(k,"occurs",v,"times")
main()
Replace:
for k,v in count.values():
With:
for k,v in count.items():
For your loop, you need both the key, k, and the value, v. count.values() will return only the values. count.items(), by contrast, will return both.
For every key check its value like this:
for key in count:
if count[key] == 1:
print(key,"occurs one time")
else:
print(key,"occurs",count[key],"times")
count.values() method returns only values in dictionary not keys. count.items() will return you key value pairs.

Resources