Combine the numbers in the brackets adjacently - python

I want to write a function to combine the numbers in the brackets adjacently.
For example, this string as the input
(4)2(2)(2)(2)2(2)
I want the output is
(4)2(6)2(2)
And for example, this string as the input
(2)(2)2(2)(2)(2)24
I want the output is
(4)2(6)24
Currently I wrote a function as follows:
def Combine(i,accumulate,s):
if s[i] == '(':
accumulate += int(s[i+1])
for i in range(i+3,len(s),3):
if s[i] == '(':
accumulate += int(s[i+1])
else:
print s[i-3] + s[i-2] + s[i-1]
i += 3
break
else:
print s[i]
i += 1
Combine(0,0,'(4)2(2)(2)(2)2(2)')
And the output is only:
(4)
I know maybe I need recursive method, but I don't know how to use it correctly.
Can anyone help me?
And I treat it as one-digit problem, and after the sum, I need to convert the number which is more than nine to a corresponding alphabet.
Following is the function:
def toStr(n,base):
convertString = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
if n < base:
return convertString[n]
else:
return toStr(n//base,base) + convertString[n%base]
So for example, the input(the base is 17):
(16)
The output needs to be:
(G)
Because I don't know how to modify the function
re.sub(r'((\(\d\))+)', f, '(2)(2)(2)(2)(2)(2)(2)(2)')
Thanks.

I'd use regex for that:
import re
def f(m):
return '({0})'.format(sum(int(x) for x in m.group(1)[1::3]))
re.sub(r'((\(\d\))+)', f, '(4)2(2)(2)(2)2(2)') # (4)2(6)2(2)
The second argument of re.sub can be a function, which you can use to compute the sum:
If repl is a function, it is called for every non-overlapping occurrence
of pattern. The function takes a single match object argument, and
returns the replacement string.
m.group(1) is the matched string, m.group(1)[1::3] is the matched string without parentheses.
sum(int(x) for x in m.group(1)[1::3]) gets us the sum of all digits in the string.
'({0})'.format(sum(int(x) for x in m.group(1)[1::3])) wraps the sum with parentheses (this is the replacement string).
Please note that the code above only works for one-digit numbers. If this is a problem, you'd use
import re
def f(m):
matched = m.group(1).strip('()').split(')(')
return '({0})'.format(sum(int(x) for x in matched))
re.sub(r'((\(\d+\))+)', f, '(42)(2)2') # (44)2

Related

Python - loop through the characters of a string until length of string reaches length of another string

I'm trying to write a function that takes two strings (message and keyword) and where the latter is shorter than the former, loop over the characters in it so that the length of both strings are the same.
eg. message = "hello", keyword = "dog" – my intended output is "dogdo" so it loops over the characters inside the keyword as many times as the length of the message
here is my attempted code which repeats the entire string rather than each individual character. ie. with message = "hell" and keyword = "do", the output will be "dodododo" instead of "dodo".
when len(keyword) is not a divisor of len(message), I have tried to have my output composed of the this plus the remainder. so for message="hello" and keyword="dog", intended output is "dogdo", but the output I get is "dogggdogggdogggdogggdoggg".
I know the way I'm looping this is wrong and I would really appreciate it if somebody could let me know why this is the case and how to get each character looped rather than the whole string.
if len(keyword) < len(message):
if len(message) % len(keyword) ==0:
for x in range(0, len(message)):
for char in keyword:
keys += char
else:
for x in range(0, len(message)):
for char in keyword:
keys += char
remainder = len(message)%len(keyword)
for x in range(0, remainder):
keys+= char
You can do some itertools magic or just write your own trivial generator as follows:
def func(message, keyword):
def gc(s):
while True:
for e in s:
yield e
g = gc(keyword)
for _ in range(len(message)-len(keyword)):
keyword += next(g)
return keyword
print(func('hello', 'dog'))
Output:
dogdo
This doesn't require any loops at all:
(keyword * ((len(message+keyword)-1)//len(keyword)))[0:len(message)]
That is, make a string of enough copies of keyword to be at least as big as message, then only take a long enough prefix of that.
You can use zip and itertools.cycle to get the effect you are looking for.
zip will iterate until the shortest iterable is exhausted and cycle will keep iterating around forever:
from itertools import cycle
message="hello"
keyword="dog"
output = ''.join([x[1] for x in zip(message, cycle(keyword))])
print(output)
Output as requested
If I've understood your request correctly, I think something like the below is what you are looking for.
The concept here is that we have a function that does the work for us that takes as input the keyword and how long you want the string to be.
It then loops until the string has become long enough, adding 1 character at a time.
def lengthen(keyword, length):
output = keyword
loop_no = 0
while len(output) < length:
char_to_add = keyword[loop_no % len(keyword)]
output += char_to_add
loop_no += 1
return output
longer_keyword_string = lengthen(keyword, len(message))

sum of numbers/extact digits

I am new to coding and try to extract and print the none digits. I've written 2 different codes but cannot combine them. I would appreciate some advices. (i tried using *args but didn't work)
def SumOfDigits(str1):
sum_digit = 0
for x in str1:
if x.isdigit():
z = int(x)
sum_digit += z
print("The sum of digits operation is", sum_digit, end=".")
return
def SumOfDigits(input):
valids = []
for character in input:
if character.isalpha():
valids.append(character)
print("The extracted non-digits are:", ''.join(valids))
return
El. Nik, i believe that those 2 function you not be merged as they are doing different behavior, which lead to a more complex function, that might get a bit confusing.
Anyway, what you want is to merge your two for loop into a single one. Since str.isalpha matches do not collide with str.isdigit ones, you can safely use a if statement followed by an elif to check every charater and apply the wanted behavior.
Then, you simply return the 2 results as a tuple.
def digit_extraction(string):
sum_digits = 0
extracted_alphas = ""
for char in string:
if char.isdigit():
sum_digits += int(char)
elif char.isalpha():
extracted_alphas += char
return sum_digits, extracted_alphas
Here is a quick example:
>>> digit_extraction("1a2b3c4d5e6f7g8h9i")
(45, 'abcdefghi')
If you dont know how multiple return value works in python, i'd suggest to check the following tutorial:
https://datagy.io/python-return-multiple-values/
To get into something more advanced, separating the 2 function would allow for writting something considered as more pythonic:
def sum_of_digits(string):
return sum(int(c) for c in string if c.isalpha())
and
def extract_alphas(string):
return ''.join(filter(str.isalpha, c))

Is there an easy way to get the number of repeating character in a word?

I'm trying to get how many any character repeats in a word. The repetitions must be sequential.
For example, the method with input "loooooveee" should return 6 (4 times 'o', 2 times 'e').
I'm trying to implement string level functions and I can do it this way but, is there an easy way to do this? Regex, or some other sort of things?
Original question: order of repetition does not matter
You can subtract the number of unique letters by the number of total letters. set applied to a string will return a unique collection of letters.
x = "loooooveee"
res = len(x) - len(set(x)) # 6
Or you can use collections.Counter, subtract 1 from each value, then sum:
from collections import Counter
c = Counter("loooooveee")
res = sum(i-1 for i in c.values()) # 6
New question: repetitions must be sequential
You can use itertools.groupby to group sequential identical characters:
from itertools import groupby
g = groupby("aooooaooaoo")
res = sum(sum(1 for _ in j) - 1 for i, j in g) # 5
To avoid the nested sum calls, you can use itertools.islice:
from itertools import groupby, islice
g = groupby("aooooaooaoo")
res = sum(1 for _, j in g for _ in islice(j, 1, None)) # 5
You could use a regular expression if you want:
import re
rx = re.compile(r'(\w)\1+')
repeating = sum(x[1] - x[0] - 1
for m in rx.finditer("loooooveee")
for x in [m.span()])
print(repeating)
This correctly yields 6 and makes use of the .span() function.
The expression is
(\w)\1+
which captures a word character (one of a-zA-Z0-9_) and tries to repeat it as often as possible.
See a demo on regex101.com for the repeating pattern.
If you want to match any character (that is, not only word characters), change your expression to:
(.)\1+
See another demo on regex101.com.
try this:
word=input('something:')
sum = 0
chars=set(list(word)) #get the set of unique characters
for item in chars: #iterate over the set and output the count for each item
if word.count(char)>1:
sum+=word.count(char)
print('{}|{}'.format(item,str(word.count(char)))
print('Total:'+str(sum))
EDIT:
added total count of repetitions
Since it doesn't matter where the repetition is occurring or which characters are being repeated, you can make use of the set data structure provided in Python. It will discard the duplicate occurrences of any character or an object.
Therefore, the solution would look something like this:
def measure_normalized_emphasis(text):
return len(text) - len(set(text))
This will give you the exact result.
Also, make sure to look out for some edge cases, which you should as it is a good practice.
I think your code is comparing the wrong things
You start by finding the last character:
char = text[-1]
Then you compare this to itself:
for i in range(1, len(text)):
if text[-i] == char: #<-- surely this is test[-1] to begin with?
Why not just run through the characters:
def measure_normalized_emphasis(text):
char = text[0]
emphasis_size = 0
for i in range(1, len(text)):
if text[i] == char:
emphasis_size += 1
else:
char = text[i]
return emphasis_size
This seems to work.

Python strings: quickly summarize the character count in order of appearance

Let's say I have the following strings in Python3.x
string1 = 'AAAAABBBBCCCDD'
string2 = 'CCBADDDDDBACDC'
string3 = 'DABCBEDCCAEDBB'
I would like to create a summary "frequency string" that counts the number of characters in the string in the following format:
string1_freq = '5A4B3C2D' ## 5 A's, followed by 4 B's, 3 C's, and 2D's
string2_freq = '2C1B1A5D1B1A1C1D1C'
string3_freq = '1D1A1B1C1B1E1D2C1A1E1D2B'
My problem:
How would I quickly create such a summary string?
My idea would be: create an empty list to keep track of the count. Then create a for loop which checks the next character. If there's a match, increase the count by +1 and move to the next character. Otherwise, append to end of the string 'count' + 'character identity'.
That's very inefficient in Python. Is there a quicker way (maybe using the functions below)?
There are several ways to count the elements of a string in python. I like collections.Counter, e.g.
from collections import Counter
counter_str1 = Counter(string1)
print(counter_str1['A']) # 5
print(counter_str1['B']) # 4
print(counter_str1['C']) # 3
print(counter_str1['D']) # 2
There's also str.count(sub[, start[, end]
Return the number of non-overlapping occurrences of substring sub in
the range [start, end]. Optional arguments start and end are
interpreted as in slice notation.
As an example:
print(string1.count('A')) ## 5
The following code accomplishes the task without importing any modules.
def freq_map(s):
num = 0 # number of adjacent, identical characters
curr = s[0] # current character being processed
result = '' # result of function
for i in range(len(s)):
if s[i] == curr:
num += 1
else:
result += str(num) + curr
curr = s[i]
num = 1
result += str(num) + curr
return result
Note: Since you requested a solution based on performance, I suggest you use this code or a modified version of it.
I have executed rough performance test against the code provided by CoryKramer for reference. This code performed the same function in 58% of the time without using external modules. The snippet can be found here.
I would use itertools.groupby to group consecutive runs of the same letter. Then use a generator expression within join to create a string representation of the count and letter for each run.
from itertools import groupby
def summarize(s):
return ''.join(str(sum(1 for _ in i[1])) + i[0] for i in groupby(s))
Examples
>>> summarize(string1)
'5A4B3C2D'
>>> summarize(string2)
'2C1B1A5D1B1A1C1D1C'
>>> summarize(string3)
'1D1A1B1C1B1E1D2C1A1E1D2B'

finding the index of the first letter of a sub string in the main string

I am trying to find the index of the first letter of a sub string within the main string. The function acts exactly like the find method of python. I have created a find_chr function that gives me the index of a character in a string and I am using the find_chr to get the index of the substring.
def find_str(s,x):
i=0
if x in s:
return find_chr(s,x[i])
else:
return -1
My problem is that when I am using the string "IS GOING GOING" and substring as "ING", I am getting the index of the first "I", when I am expecting the index of the "I" of "ING". I will appreciate any input about changing the function to get the right index of the first letter of the substring.
In find_str you call find_chr(s,x[i]). This is calling find_chr with only x[i] (the ith part of the substring).
This should fix your problem
def find_chr(s,char):
i=0
step = len(char)
for j in range(len(s)+1):
ch = s[j:j+step]
if ch==char:
return (i)
break
i+=1
return -1
def find_str(s,x):
i=0
if x in s:
return find_chr(s,x)
else:
return -1
You aren't looping through the characters, you only check for i == 0 (i.e. the first character in s). You need to apply a "window" to the string, checking len(s) characters in a row:
def find_str(s, x):
if x in s: # is x present?
for i in range(len(s)): # work through string indices
if s[i:i+len(x)] == x: # does x start at current index?
return i
return -1
This should solve your problem:
def find_str(s, x):
i = 0
while i < len(s):
if s[i:i + len(x)] == x:
return i
else:
i += 1
print find_str('IS GOING GOING', 'ING')
Look up the use of the index function in strings. You will then happily replace all of that code with about 1 line.
Supplying the answer because of the following comments. Seriously though, if one is going to learn python, it is a good exercise to be aware of the methods available for an object.
>>> 'is going going'.index('ing')
5
or more generally
>>> fullstring.index(substring)
This should be marked as the correct answer because it is the simplest and most obviously correct. The complexity of the algorithms offered is way too high for this problem.
If the substring is not in the fullstring, a ValueError exception will be raised. So if you need a function, then it should return the index from a try or -1 (or None) from the except blocks.

Categories