Related
if i just read my sum_digits function here, it makes sense in my head but it seems to be producing wrong results. Any tip?
def is_a_digit(s):
''' (str) -> bool
Precondition: len(s) == 1
Return True iff s is a string containing a single digit character (between
'0' and '9' inclusive).
>>> is_a_digit('7')
True
>>> is_a_digit('b')
False
'''
return '0' <= s and s <= '9'
def sum_digits(digit):
b = 0
for a in digit:
if is_a_digit(a) == True:
b = int(a)
b += 1
return b
For the function sum_digits, if i input sum_digits('hihello153john'), it should produce 9
Notice that you can easily solve this problem using built-in functions. This is a more idiomatic and efficient solution:
def sum_digits(digit):
return sum(int(x) for x in digit if x.isdigit())
print(sum_digits('hihello153john'))
=> 9
In particular, be aware that the is_a_digit() method already exists for string types, it's called isdigit().
And the whole loop in the sum_digits() function can be expressed more concisely using a generator expression as a parameter for the sum() built-in function, as shown above.
You're resetting the value of b on each iteration, if a is a digit.
Perhaps you want:
b += int(a)
Instead of:
b = int(a)
b += 1
Another way of using built in functions, is using the reduce function:
>>> numeric = lambda x: int(x) if x.isdigit() else 0
>>> reduce(lambda x, y: x + numeric(y), 'hihello153john', 0)
9
One liner
sum_digits = lambda x: sum(int(y) for y in x if y.isdigit())
I would like to propose a different solution using regx that covers two scenarios:
1.
Input = 'abcd45def05'
Output = 45 + 05 = 50
import re
print(sum(int(x) for x in re.findall(r'[0-9]+', my_str)))
Notice the '+' for one or more occurrences
2.
Input = 'abcd45def05'
Output = 4 + 5 + 0 + 5 = 14
import re
print(sum(int(x) for x in re.findall(r'[0-9]', my_str)))
Another way of doing it:
def digit_sum(n):
new_n = str(n)
sum = 0
for i in new_n:
sum += int(i)
return sum
An equivalent for your code, using list comprehensions:
def sum_digits(your_string):
return sum(int(x) for x in your_string if '0' <= x <= '9')
It will run faster then a "for" version, and saves a lot of code.
Just a variation to #oscar's answer, if we need the sum to be single digit,
def sum_digits(digit):
s = sum(int(x) for x in str(digit) if x.isdigit())
if len(str(s)) > 1:
return sum_digits(s)
else:
return s
#if string =he15ll15oo10
#sum of number =15+15+10=40
def sum_of_all_Number(s):
num = 0
sum = 0
for i in s:
if i.isdigit():
num = num * 10 + int(i)
else:
sum = sum + num
num = 0
return sum+num
#if string =he15ll15oo10
#sum of digit=1+5+1+5+1+0=13
def sum_of_Digit(s):
sum = 0
for i in s:
if i.isdigit():
sum= sum + int(i)
return sum
s = input("Enter any String ")
print("Sum of Number =", sum_of_all_Number(s))
print("Sum Of Digit =", sum_of_Digit(s))
simply turn the input to integer by int(a) ---> using a.isdigit to make sure the input not None ('') ,
if the input none make it 0 and return sum of the inputs in a string simply
def sum_str(a, b):
a = int(a) if a.isdigit() else 0
b = int(b) if b.isdigit() else 0
return f'{a+b}'
Define a function max_even_digs(..) which receives as input one string containing digits, letters or special symbols.The function should return an integer number containing the maximum value among all the even digits in the string. If there are no even digits in the string, the function should return -1.
def max_even_digs(st):
digits = "1234567890"
print(len(st))
for i in range(len(st)):
if (i % 2 == 0) and st[i] in digits:
if st[i] > st[i+1]:
solution = st[i]
else:
solution = st[i+1]
return solution
As an example, the following snippet of code fragment:
print (max_even_digs("a1b8c9!$4"))
should produce the output as: 8
Because you are comparing st[i] with st[i+1], you must iterate only until the 2nd to last item in the string:
however,
in the present case, your logic is also flawed. The next digit you are returning may not be the correct solution:
Here is an approach:
def max_even_digs(st):
max_even = 0
for elt in st:
if elt.isdigit() and int(elt) % 2 == 0:
if int(elt) > max_even:
max_even = int(elt)
return max_even
Or, this one if you prefer conciseness:
def max_even_digs(st):
return max(int(elt) for elt in st if elt.isdigit() and int(elt) % 2 == 0)
Actually, a integer has a ASC-II code between 48 and 57.
chr(48)
'0'
ord('9')
57
So, one can search the ASC-II of the string, saying
def max_even_digs(astr):
result = -1
for c in astr:
if 48 <= ord(c) < 57 and ord(c) % 2 == 0: # or ord(c) in [48,50,52,54,56]
if int(c) > result:
result = int(c)
return result
You can use following as alternative solution:
def max_even_digs(st):
res = [int(s) for s in st if s.isdigit() and int(s) % 2 ==0]
res.append(-1)
return max(res)
print (max_even_digs("a1b8c9!$4"))
print (max_even_digs("abc"))
what I'm trying to implement is a function that increments a string by one character, for example:
'AAA' + 1 = 'AAB'
'AAZ' + 1 = 'ABA'
'ZZZ' + 1 = 'AAAA'
I've implemented function for the first two cases, however I can't think of any solution for the third case.
Here's my code :
def new_sku(s):
s = s[::-1]
already_added = False
new_sku = str()
for i in s:
if not already_added:
if (i < 'Z'):
already_added = True
new_sku += chr((ord(i)+1)%65%26 + 65)
else:
new_sku += i
return new_sku[::-1]
Any suggestions ?
If you're dealing with bijective numeration, then you probably have (or should have) functions to convert to/from bijective representation anyway; it'll be a lot easier just to convert to an integer, increment it, then convert back:
def from_bijective(s, digits=string.ascii_uppercase):
return sum(len(digits) ** i * (digits.index(c) + 1)
for i, c in enumerate(reversed(s)))
def to_bijective(n, digits=string.ascii_uppercase):
result = []
while n > 0:
n, mod = divmod(n - 1, len(digits))
result += digits[mod]
return ''.join(reversed(result))
def new_sku(s):
return to_bijective(from_bijective(s) + 1)
How about ?
def new_sku(s):
s = s[::-1]
already_added = False
new_sku = str()
for i in s:
if not already_added:
if (i < 'Z'):
already_added = True
new_sku += chr((ord(i)+1)%65%26 + 65)
else:
new_sku += i
if not already_added: # carry still left?
new_sku += 'A'
return new_sku[::-1]
Sample run :-
$ python sku.py Z
AA
$ python sku.py ZZZ
AAAA
$ python sku.py AAA
AAB
$ python sku.py AAZ
ABA
You have to think of 'AAA', 'ZZZ', ... as representation of the value you manipulate.
First, parse the value:
val = sum(pow(26, i) * (ord(v) - ord('A') + 1) for i, v in enumerate(value[::-1]))
Then, add value to it:
val = val + 1
Edit
The final value is given by:
res = ""
while val > 0:
val, n = divmod(val - 1, 26)
res = chr(n+ord('A')) + res
The lack of representation for zero requires the value passed to divmod to be decremented at each turn, which i have not found a way of doing with a list comprehension.
Edit
Rather than ord() and chr(), it is possible to use string.ascii_uppercase.index() and string.ascii_uppercase[]
You can make use of some recursion here:
def new_sku(s):
s = s[::-1]
new_s = ''
return expand(s.upper(), new_s)[::-1]
import string
chars = string.ascii_uppercase
def expand(s, new_s, carry_forward=True):
if not s:
new_s += 'A' if carry_forward else ''
return new_s
new_s += chars[(ord(s[0]) - ord('A') + carry_forward) % 26]
# Slice the first character, and expand rest of the string
if s[0] == 'Z':
return expand(s[1:], new_s, carry_forward)
else:
return expand(s[1:], new_s, False)
print new_sku('AAB')
print new_sku('AAZ')
print new_sku('ZZZ')
print new_sku('aab')
print new_sku('aaz')
print new_sku('zzz')
Output:
AAC
ABA
AAAA
AAC
ABA
AAAA
I would implement this like a base-26 addition with carry.
So start from the right of the string, add 1. If it reaches Z, wrap to A and bump the next left most character up one. If the left most character reaches Z, add an A to the left of the string.
s = ["Z","Z","Z"]
done = 0
index = len(s) - 1
while done == 0:
if s[index] < "Z":
s[index] = chr(ord(s[index]) + 1)
done = 1
else:
s[index] = "A"
if index == 0:
s = ["A"] + s
done = 1
else:
index = index - 1
print s
Just check if the string is all Zs, and if it is, replace it by a string with length len(s) + 1, consisting of just As:
if s == "Z" * len(s):
return "A" * (len(s) + 1)
alp='ABCDEFGHIJKLMNOPQRSTUVWXYZA'
def rec(s):
if len(s)==0:return 'A'
last_letter=s[-1]
if last_letter=='Z':return rec(s[:-1])+'A'
return s[:-1]+alp[(alp.find(last_letter)+1)]
result
>>> rec('AAA')
'AAB'
>>> rec('AAZ')
'ABA'
>>> rec('ZZZ')
'AAAA'
>>> rec('AZA')
'AZB'
How about this? As a simple way to handle the string getting longer you can prepend a leading '#' and strip it if it wasn't incremented:
>>> def new_sku(s):
def increment(s):
if s.endswith('Z'):
return increment(s[:-1])+'A'
else:
return s[:-1]+chr(ord(s[-1])+1)
t = increment('#'+s)
return t.lstrip('#')
>>> new_sku('AAA')
'AAB'
>>> new_sku('AAZ')
'ABA'
>>> new_sku('ZZZ')
'AAAA'
If the recursion worries you then you can flatten it the way you already did but still use the '#' character added and stripped.
You can use a for-else loop:
from string import ascii_uppercase as au
def solve(strs):
lis = []
for i, c in enumerate(strs[::-1], 1):
ind = au.index(c) + 2
lis.append(au[(ind%26)-1])
if ind <= 26:
break
else:
# This will execute only if the for-loop didn't break.
lis.append('A')
return strs[:-1*i] + "".join(lis[::-1])
print solve('AAA')
print solve('AAZ')
print solve('ZZZ')
print solve('AZZZ')
print solve('ZYZZ')
print solve('ZYYZZ')
output:
AAB
ABA
AAAA
BAAA
ZZAA
ZYZAA
We can see there are 3 conditions totally, you can iterate the string and process one of the conditions.
You can use the string.ascii_uppercase instead of chr and ord
import string
def add(s):
s = list(s)[::-1]
for index, char in enumerate(s):
if char != "Z":
s[index] = string.ascii_uppercase[string.ascii_uppercase.index(char) + 1]
return s[::-1]
elif char == "Z" and (index != len(s) - 1):
s[index] = "A"
elif char == "Z" and (index == len(s) - 1):
s[index] = "A"
return ["A"] + s[::-1]
if i just read my sum_digits function here, it makes sense in my head but it seems to be producing wrong results. Any tip?
def is_a_digit(s):
''' (str) -> bool
Precondition: len(s) == 1
Return True iff s is a string containing a single digit character (between
'0' and '9' inclusive).
>>> is_a_digit('7')
True
>>> is_a_digit('b')
False
'''
return '0' <= s and s <= '9'
def sum_digits(digit):
b = 0
for a in digit:
if is_a_digit(a) == True:
b = int(a)
b += 1
return b
For the function sum_digits, if i input sum_digits('hihello153john'), it should produce 9
Notice that you can easily solve this problem using built-in functions. This is a more idiomatic and efficient solution:
def sum_digits(digit):
return sum(int(x) for x in digit if x.isdigit())
print(sum_digits('hihello153john'))
=> 9
In particular, be aware that the is_a_digit() method already exists for string types, it's called isdigit().
And the whole loop in the sum_digits() function can be expressed more concisely using a generator expression as a parameter for the sum() built-in function, as shown above.
You're resetting the value of b on each iteration, if a is a digit.
Perhaps you want:
b += int(a)
Instead of:
b = int(a)
b += 1
Another way of using built in functions, is using the reduce function:
>>> numeric = lambda x: int(x) if x.isdigit() else 0
>>> reduce(lambda x, y: x + numeric(y), 'hihello153john', 0)
9
One liner
sum_digits = lambda x: sum(int(y) for y in x if y.isdigit())
I would like to propose a different solution using regx that covers two scenarios:
1.
Input = 'abcd45def05'
Output = 45 + 05 = 50
import re
print(sum(int(x) for x in re.findall(r'[0-9]+', my_str)))
Notice the '+' for one or more occurrences
2.
Input = 'abcd45def05'
Output = 4 + 5 + 0 + 5 = 14
import re
print(sum(int(x) for x in re.findall(r'[0-9]', my_str)))
Another way of doing it:
def digit_sum(n):
new_n = str(n)
sum = 0
for i in new_n:
sum += int(i)
return sum
An equivalent for your code, using list comprehensions:
def sum_digits(your_string):
return sum(int(x) for x in your_string if '0' <= x <= '9')
It will run faster then a "for" version, and saves a lot of code.
Just a variation to #oscar's answer, if we need the sum to be single digit,
def sum_digits(digit):
s = sum(int(x) for x in str(digit) if x.isdigit())
if len(str(s)) > 1:
return sum_digits(s)
else:
return s
#if string =he15ll15oo10
#sum of number =15+15+10=40
def sum_of_all_Number(s):
num = 0
sum = 0
for i in s:
if i.isdigit():
num = num * 10 + int(i)
else:
sum = sum + num
num = 0
return sum+num
#if string =he15ll15oo10
#sum of digit=1+5+1+5+1+0=13
def sum_of_Digit(s):
sum = 0
for i in s:
if i.isdigit():
sum= sum + int(i)
return sum
s = input("Enter any String ")
print("Sum of Number =", sum_of_all_Number(s))
print("Sum Of Digit =", sum_of_Digit(s))
simply turn the input to integer by int(a) ---> using a.isdigit to make sure the input not None ('') ,
if the input none make it 0 and return sum of the inputs in a string simply
def sum_str(a, b):
a = int(a) if a.isdigit() else 0
b = int(b) if b.isdigit() else 0
return f'{a+b}'
I'm trying to create a loop to generate and print strings as follows:
Alphanumeric characters only:
0-9 are before A-Z, which are before a-z,
Length goes up to 4 characters.
So, it would print:
all strings from 0-z
then from 00-zz
then from 000-zzz
then from 0000-zzzz
then it stops.
from string import digits, ascii_uppercase, ascii_lowercase
from itertools import product
chars = digits + ascii_uppercase + ascii_lowercase
for n in range(1, 4 + 1):
for comb in product(chars, repeat=n):
print ''.join(comb)
This first makes a string of all the numbers, uppercase letters, and lowercase letters.
Then, for each length from 1-4, it prints every possible combination of those numbers and letters.
Keep in mind this is A LOT of combinations -- 62^4 + 62^3 + 62^2 + 62.
I dislike the answer given before me using product since looking at its implementation in the python documentation it seem to span the entire thing into a list in memory before starting to yield the results.
This is very bad for your case since, as agf himself said, the number of permutation here is huge (well over a million). For this case the yield statement was created - so that huge lists could be dynamically generated rather than spanned in memory (I also disliked the wasteful range where xrange is perfectly applicable).
I'd go for a solution like this:
def generate(chars, length, prefix = None):
if length < 1:
return
if not prefix:
prefix = ''
for char in chars:
permutation = prefix + char
if length == 1:
yield permutation
else:
for sub_permutation in generate(chars, length - 1, prefix = permutation):
yield sub_permutation
This way, all that spans in memory is a recursive stack "n" deep, where "n" is the length of your permutations (4 in this case) and only a single element is returned each time.
chars is the set of chars to choose from, length is 4 and the use is rather similar to products, except that it doesn't span the whole list in memory during run time.
I coded this today. It does exactly what you want and more. It's extendable as well
def lastCase (lst):
for i in range(0, len(lst)):
if ( lst[i] != '_' ):
return False
return True
l = [''] * 4 #change size here if needed. I used 4
l[0] = '0'
index = 0
while ( not lastCase(l) ):
if ( ord(l[index]) > ord('_') ):
l[index] = '0'
index += 1
while( l[index] == '_' ):
l[index] = '0'
index += 1
if (l[index] == ''):
l[index] = '0'
#print or process generated string
print(''.join(l))
l[index] = chr(ord(l[index]) +1)
if ( ord(l[index]) > ord('9') and ord(l[index]) < ord('A') ):
l[index] = 'A'
elif ( ord(l[index]) > ord('Z') and ord(l[index]) < ord('_') ):
l[index] = '_'
index = 0
print (''.join(l))
from string import digits, ascii_uppercase, ascii_lowercase
from itertools import product
chars = digits + ascii_uppercase + ascii_lowercase
def give_me_next(lst):
lst = lst[::-1]
change_next = False
change = True
n = 0
for x in lst:
if change_next == True:
change_next = False
pos = chars.find(x)
try:
a = chars[pos+1]
lst = list(lst)
lst[n] = a
lst = "".join(lst)
x = a
except:
lst = list(lst)
lst[n] = '0'
lst = "".join(lst)
change_next = True
x = '0'
pos = chars.find(x)
try:
a = chars[pos+1]
if change == True:
lst = list(lst)
lst[n] = a
lst = "".join(lst)
change = False
except:
lst = list(lst)
lst[n] = '0'
lst = "".join(lst)
change_next = True
n = n + 1
lst = lst[::-1]
return lst
a= give_me_next('zzzzz')
while True:
a = give_me_next(a)
print a
This seems like the simplest solution to me:
from string import digits, ascii_uppercase, ascii_lowercase
chars = digits + ascii_uppercase + ascii_lowercase
all_str = [''.join([a]) for a in chars] \
+ [''.join([a,b]) for a in chars for b in chars] \
+ [''.join([a,b,c]) for a in chars for b in chars for c in chars] \
+ [''.join([a,b,c,d]) for a in chars for b in chars for c in chars for d in chars]
print(all_str)
print("Number of strings:", len(all_str))
Example for strings with maximum 2 characters.
Of course, there may be a way to generalize to any max number of characters per string, but since you have a specific need for strings up to 4 characters, it's fine.