Given an arbitrary input string I'm meant to find the sum of all numbers in that string.
This obviously requires that i know the NEXT element in string while iterating through it...and make the decision whether its an integer. if the previous element was an integer also, the two elements form a new integer, all other characters are ignored and so on.
For instance an input string
ab123r.t5689yhu8
should result in the sum of 123 + 5689 + 8 = 5820.
All this is to be done without using regular expressions.
I have implemented an iterator in python, whose (next()) method i think returns the next element, but passing the input string
acdre2345ty
I'm getting the following output
a
c
d
r
e
2
4
t
y
Some numbers 3 and 5 are missing...why is this? I need that the next() to work for me to be able to sift through an input string and do the calculations correctly
Better still, how should i implement the next method so that it yields the element to the immediate right during a given iteration?
Here is my code
class Inputiterator(object):
'''
a simple iterator to yield all elements from a given
string successively from a given input string
'''
def __init__(self, data):
self.data = data
self.index = 0
def __iter__(self):
return self
def next(self):
"""
check whether we've reached the end of the input
string, if not continue returning the current value
"""
if self.index == len(self.data)-1:
raise StopIteration
self.index = self.index + 1
return self.data[self.index]
# Create a method to get the input from the user
# simply return a string
def get_input_as_string():
input=raw_input("Please enter an arbitrary string of numbers")
return input
def sort_by_type():
maininput= Inputiterator(get_input_as_string())
list=[]
s=""
for char in maininput:
if str(char).isalpha():
print ""+ str(char)
elif str(char).isdigit() and str(maininput.next()).isdigit():
print ""+ str(char)
sort_by_type()
Python strings are already iterable, no need to create you own iterator.
What you want is thus simply achieved without iterators:
s = "acdre2345ty2390"
total = 0
num = 0
for c in s:
if c.isdigit():
num = num * 10 + int(c)
else:
total += num
num = 0
total += num
Which results in:
>>> print total
4735
This can be done with itertools.groupby:
from itertools import groupby
s = 'ab123r#t5689yhu8'
tot = 0
for k, g in groupby(s, str.isdigit):
if k:
tot += int(''.join(g))
Or in one line (as suggested in the comments down below):
tot = sum((int(''.join(g)) for k, g in groupby(s, str.isdigit) if k)
Edit: I first deleted this answer as there are much better solutions for your problem in this thread, but as you are directly asking how to use the next method to get your code working I have recovered it, in case you find it useful.
Try this (I mocked the iterator for convenience):
def sort_by_type():
maininput = iter("acdre2345ty")
for char in maininput:
if char.isalpha():
print char
elif char.isdigit():
number = char
while True:
# try/except could take care of the StopIteration exception
# when a digit is last in the string
#
# try:
# char = maininput.next()
# except StopIteration:
# char = ""
#
# however using next(iterator, default) is much better:
#
char = next(maininput, "")
if char.isdigit():
number += char
else:
break
print number
print char
if produces:
a
c
d
r
e
2345
t
y
For entertainment purposes only (I couldn't resist, 49 chars):
eval(''.join([['+0+',x][x.isdigit()]for x in s]))
Related
I'm trying to write a function to find the text from a sum of ascii numbers. All characters are uppercase , and if for example I get 155 , the function need to return AZ (65+90). Think of it like columns in an Excel table: it goes from A to Z, then AA, AB...AZ, BA, BB and etc. It needs to work for up to 4 digits. I'm trying a recursive function, but it has some errors. If I give the function 270 -> it return AAAK, not ZZZ , because I check if 65(A) fits in that number, then I go to the next if it doesn't (with the second if: number % asc + asc). Another error is in the output of the code: 130+90 works well , AAZ, but if I add 1 it should give me ABA. In these cases I think I'm doing things wrong the most. Initially I wanted to use integer division (//) and modulo (%), but it didn't work.
def ascii(number):
result = ""
if number > 90:
for asc in range(65, 91):
if number % asc + asc in range(65, 91):
result += chr(asc)
result += ascii(number - asc)
break
else:
result += chr(number)
return result
if __name__ == '__main__':
result = ""
print(ascii(131))
print(ascii(130+90))
print(ascii(130+90+1))
print(ascii(130+90+39))
#output: AB, AAZ, BAZ, UTZ
Searching recursively is fine, the problem is that you don't set a limit to how deep it need to go, that is why for 270 it goes 4 levels to AAAK and not 3 to ZZZ.
So first we need to determine how deep we need to go, then the base case for the recursive function now become: in the base level return the character if the value is correct otherwise return nothing, and for the rest, for each character, we check if we get a result from the recursive case, if we do we're done otherwise we continue and if no match simple return nothing.
Something like
import itertools
A = ord("A")
Z = ord("Z")
def length(num):
if num < A:
return 0
for n in itertools.count(1):
if A*n <= num <= Z*n:
return n
elif num <= A*n:
break
return 0
def search_ascii(num, level):
if level<1:
return ""
if level==1:
if A <= num <= Z:
return chr(num)
return ""
for n in range(A,1+Z):
r = search_ascii(num-n,level-1)
if r:
return chr(n)+r
return ""
def to_ascii(num):
n = length(num)
if not n:
raise ValueError("value too small")
return search_ascii(num,n)
print(to_ascii(131))
print(to_ascii(130+90))
print(to_ascii(130+90+1))
print(to_ascii(130+90+39))
print(to_ascii(270))
print(to_ascii(155))
and the output
AB
AAZ
ABZ
OZZ
ZZZ
AZ
the non-recursive version can be done with itertools.product like so:
def to_ascii_it(num):
n = length(num)
if not n:
raise ValueError("value too small")
for chars in itertools.product(range(A,1+Z), repeat=n):
if sum(chars)==num:
return "".join(map(chr,chars))
I have this string 0123456789 and I want to use recursion to create a method that returns
'09182736455463728190'
So basically the above says that first I get the first num from the left and then the first from the right, and add them to the string, then I get the second from the left and the second from the right, etc.
When I reach the middle, I start adding to the final string the values of the initial string, but now int the opposite order. So 546372, etc. So Starting from the edges I add first the most left and then the most right element.
Starting from the middle and moving to the edges, I favour the right side element first.
I cannot come up with the recursion relationship
Here it is. The base case is when the final string length is twice the original string length. This signals the end of recursion and returns the final string. The recursive step consists of advancing the start index forward and the end index backward on the original string:
def transform_sequence(original, final = '', start_index = 0, end_index = -1):
#base case:
if len(final) == 2* len(original):
return final
#recursion
final += original[start_index] + original[end_index]
return transform_sequence(original, final, start_index + 1, end_index - 1)
print(transform_sequence('0123456789'))
#output: 09182736455463728190
If you want to use recursion to handle this, you'd better try to solve it from top-down like this
def rec(nums):
if len(nums) == 0:
return ''
elif len(nums) == 1:
return nums * 2
else:
first = nums[0]
last = nums[-1]
return ''.join([first, last, rec(nums[1:-1]), last, first])
if __name__ == '__main__':
nums = '0123456789'
print(rec(nums)) # 09182736455463728190
nums = '012'
print(rec(nums)) # 021120
nums = '0'
print(rec(nums)) # 00
Fun problem and great way to learn about recursion. We can use inductive reasoning to ensure our program is valid for all input strings -
if the input s is empty, return the empty result
(inductive) s is not empty. get the first and last characters, a and b, and prepend/append them to the result of the sub-problem, s[1:-1]
We can easily encode this in python -
def first_and_last(s):
return (s[0], s[-1])
def puzzle(s):
if not s:
return "" # 1
else:
(a,b) = first_and_last(s) # 2
return a + b + puzzle(s[1:-1]) + b + a
We can see it working below -
print(puzzle("0123456789"))
print(puzzle("12345"))
09182736455463728190
152433334251
When then puzzle input is an odd length, notice how the middle character is repeated four times. When we reach the sub-problem puzzle("3"), a=3 and b=3, and the result of a + b + puzzle("") + b + a is 3333.
If you wish to handle this situation differently, we could modify puzzle
def puzzle(s):
if len(s) < 2: # <- if input is empty or singleton string
return s # <- return s
else:
(a,b) = first_and_last(s)
return a + b + puzzle(s[1:-1]) + b + a
print(puzzle("0123456789"))
print(puzzle("12345"))
09182736455463728190
152434251 # <-
The nice answer from Menglong Li presents another option for dealing with puzzle inputs of an odd length. I encourage you to see it :D
I'd take a different approach to this problem and assume the argument is a sequence rather than a str. This simplifies our logic, allowing us to pass str to the initial call, but the recursive calls can pass list:
def puzzle(sequence):
if len(sequence) > 1:
first, *middle, last = sequence
return first + last + puzzle(middle) + last + first
return sequence[0] if sequence else ""
if __name__ == '__main__':
print(puzzle("0123456789"))
print(puzzle("12345"))
print(puzzle("012"))
print(puzzle("0"))
OUTPUT
> python3 test.py
09182736455463728190
152434251
02120
0
>
If you approach this as processing the first character (placing it at the beginning and end) and recursing with the inverted remainder of the string then your exit condition will be an empty string:
def mirror(S):
return "" if not S else S[0]+mirror(S[:0:-1])+S[0]
print(mirror("0123456789")) # 09182736455463728190
If you want to avoid generating new (inverted) strings on every recursion, you could also implement it using an index that you carry along and map to alternating start/end relative positions:
def mirror(S,i=0):
j = (i+1)//2 * (-1)**i
return S[j]+mirror(S,i+1)+S[j] if i<len(S) else ""
I don't know why, but I am getting value of scope as final as 0 even len(s) as zero in the last line of countfrequency(s) function.
import collections
def countfrequency(s):
final = 0
flag = 1
d = dict(collections.Counter(s))
for item in d:
if d[item] <= k:
flag = 0
if flag == 1: #Here
final = max(final, len(s))
print(final)
s = "ababbc"
k = 2
for x in range(len(s)):
for y in range(1, len(s)):
countfrequency(s[x:y + 1])
It is because of 2 reasons :
Value of flag is 0 at last so it wont change the value of final
Length function takes object as a parameter and when unchanged it gives 0
So you can can either make flag 1 so that control goes inside if condition or print the value of len(s) out side the if condition
In addition to the answer posted by shaktiraj jadeja, the modified code is as follows:
import collections
def countfrequency(s, k):
final = 0
flag = 0
d = dict(collections.Counter(s))
# print(d)
for item in d:
if d[item] > k:
flag = 1
break
if flag == 1: #Here
# print("Inside:", final, len(s))
final = max(final, len(s))
print(final)
s = "ababbc"
k = 2
for x in range(len(s)):
for y in range(1, len(s)):
# print(s[x:y])
countfrequency(s[x:y + 1], k)
To start with there is no problem of scope.
Now lets get back to the problem
Lets define a rule.
Rule: If a sub string has each character repeated more than k(=2) times in it. Then it is a good substring. Else it is a bad substring
Then your code simply prints the length of good sub string or 0 in case of bad substring
In short in your example string s= "ababbc" contains no good substring
if you try S = "aaaaaa" you will see many numbers printed other than 0 (exactly 11 0's and 10 other numbers)
Now either this was your confusion or you wrote the wrong code for some logic
I hope this helps
I'm currently learning to create generators and to use itertools. So I decided to make a string index generator, but I'd like to add some parameters such as a "start index" allowing to define where to start generating the indexes.
I came up with this ugly solution which can be very long and not efficient with large indexes:
import itertools
import string
class StringIndex(object):
'''
Generator that create string indexes in form:
A, B, C ... Z, AA, AB, AC ... ZZ, AAA, AAB, etc.
Arguments:
- startIndex = string; default = ''; start increment for the generator.
- mode = 'lower' or 'upper'; default = 'upper'; is the output index in
lower or upper case.
'''
def __init__(self, startIndex = '', mode = 'upper'):
if mode == 'lower':
self.letters = string.ascii_lowercase
elif mode == 'upper':
self.letters = string.ascii_uppercase
else:
cmds.error ('Wrong output mode, expected "lower" or "upper", ' +
'got {}'.format(mode))
if startIndex != '':
if not all(i in self.letters for i in startIndex):
cmds.error ('Illegal characters in start index; allowed ' +
'characters are: {}'.format(self.letters))
self.startIndex = startIndex
def getIndex(self):
'''
Returns:
- string; current string index
'''
startIndexOk = False
x = 1
while True:
strIdMaker = itertools.product(self.letters, repeat = x)
for stringList in strIdMaker:
index = ''.join([s for s in stringList])
# Here is the part to simpify
if self.startIndex:
if index == self.startIndex:
startIndexOk = True
if not startIndexOk:
continue
###
yield index
x += 1
Any advice or improvement is welcome. Thank you!
EDIT:
The start index must be a string!
You would have to do the arithmetic (in base 26) yourself to avoid looping over itertools.product. But you can at least set x=len(self.startIndex) or 1!
Old (incorrect) answer
If you would do it without itertools (assuming you start with a single letter), you could do the following:
letters = 'abcdefghijklmnopqrstuvwxyz'
def getIndex(start, case):
lets = list(letters.lower()) if case == 'lower' else list(letters.upper())
# default is 'upper', but can also be an elif
for r in xrange(0,10):
for l in lets[start:]:
if l.lower() == 'z':
start = 0
yield ''.join(lets[:r])+l
I run until max 10 rows of letters are created, but you could ofcourse use an infinite while loop such that it can be called forever.
Correct answer
I found the solution in a different way: I used a base 26 number translator (based on (and fixxed since it didn't work perfectly): http://quora.com/How-do-I-write-a-program-in-Python-that-can-convert-an-integer-from-one-base-to-another)
I uses itertools.count() to count and just loops over all the possibilities.
The code:
import time
from itertools import count
def toAlph(x, letters):
div = 26
r = '' if x > 0 else letters[0]
while x > 0:
r = letters[x % div] + r
if (x // div == 1) and (x % div == 0):
r = letters[0] + r
break
else:
x //= div
return r
def getIndex(start, case='upper'):
alphabet = 'abcdefghijklmnopqrstuvwxyz'
letters = alphabet.upper() if case == 'upper' else alphabet
started = False
for num in count(0,1):
l = toAlph(num, letters)
if l == start:
started = True
if started:
yield l
iterator = getIndex('AA')
for i in iterator:
print(i)
time.sleep(0.1)
I have a homework assignment asking for string length calculation without using built-in functions.
What I had in mind is to use a counter:
s = 0
while name[s] != "":
s += 1
but I'm stuck with how to solve the string index out of range error...or is there actually another way?
you have two simple options :
Either add a try/except clause:
s = 0
try:
while(name[s]):
s += 1
except IndexError:
pass
print(s)
Or use an iterator:
s = 0
for _ in name:
s += 1
print(s)
Try this,
counter = 0
st = 'ABCDEF'
for i in st:
counter += 1
print('Length of String is : ', str(counter))
So, a string is basically a sequence of characters. For example:
'hello' = ['h', 'e', 'l', 'l', 'o']
So if you just loop through this array and add 1 to your length variable every loop, you will get the length:
string = "hello"
length = 0
for character in string:
length = length + 1
print(length)
This way, you won't even need to worry about handling exceptions :)
Try it online
https://repl.it/IptA/0
Further Reading
Strings
Lists
There is an alternative to the "stupid" counting by adding one for each character:
An exponential search finds a range for the string length.
A binary search pins down the string length starting with the range, found in the previous step.
The code with test section:
def is_valid_index(s, i):
'''Returns True, if i is a valid index of string s, and False otherwise.'''
try:
s[i]
return True
except IndexError:
return False
def string_length(s):
'''Returns the length of string s without built-ins.'''
# Test for empty string (needed for the invariant
# of the following exponential search.)
if not is_valid_index(s, 0):
return 0
# Exponential search with low as inclusive lower bound
# and high as exclusive upper bound.
# Invariant for the loop: low is a valid index.
low = 0
high = 1
while True:
if is_valid_index(s, high):
low = high
high *= 2
continue
break
# Binary search inside the found range
while True:
if low + 1 == high:
return high
middle = (low + high) // 2
if is_valid_index(s, middle):
low = middle
else:
high = middle
# Test section
print(string_length('hello'))
# Test the first thousand string lengths
for i in range(1000):
s = 'x' * i
if len(s) != string_length(s):
print('Error for {}: {}'.format(i, string_length(s)))
# Test quite a large string
s = 'x' * 1234567890
print(string_length(s))
Result:
5
1234567890
A string has an attribute __len__, a function that returns the length of the string. Thus, the following solution does not use built-ins, but the calculation is trivial (without calculating operations, thus, it might be not the intention of the homework):
def get_string_length(s):
return s.__len__()
Test:
print(get_string_length('hello'))
Result:
5