Python character math using stack - python

I received an interesting challenge in an algorithm Meetup. Given an input string, return a string in which all substrings within brackets have been replicated n times, where n is the integer outside the brackets. Characters outside brackets should simply be concatenated to the substring inside. For example:
2[ab] should return abab
a[3[bc]] should return abcbcbc
2[ab[cd]] should return abcdabcd
I've started implementing the solution using a stack, but I've got the feeling that my approach of checking each de-stacked character for a bracket is off, anyone have any suggestions? Code is below
class Stack:
def __init__(self):
self.items = []
def push(self, item):
self.items.append(item)
def pop(self):
return self.items.pop()
def length(self):
return len(self.items)
def is_number(s):
try:
int(s)
return True
except ValueError:
return False
def character_math(charstr):
final_output = ""
substring = ""
for i in charstr:
myStack.push(i)
for m in range(myStack.length() - 2):
destacked = myStack.pop()
# We want to go to the inner-most right bracket
if destacked != "]":
substring += destacked
if destacked == "[":
possible_multiplier = myStack.pop()
if is_number(possible_multiplier):
final_output += int(possible_multiplier) * substring
else:
final_output += possible_multiplier[::-1]
break
final_output += substring[::-1]
return "Final output is ", final_output
myStack = Stack()
# 3[ab[cd]] should return 'abcdabcd'
sample_str = '2[ab[cd]]'
print(character_math(sample_str))

The best way to do that is to use a recursive algorithm. The idea is to repeat a function until a condition is match. Here is the code I used, it works on your examples, and I don't think I forgot one of the possibilities.
# -*-coding:Utf-8 -*
Input = "2[ab[cd]]"
def Treatment(STR):
# Exit the treatment. That's the end condition.
if "[" not in STR:
return STR
# Find the inner [], in this case, the "cd" part
Bound1_ID = len(STR) - STR[::-1].index("[") - 1
Bound2_ID = STR.index("]")
# Separate STR into : First_part + middle between [] + Last_part
Last_part = STR[Bound2_ID + 1:]
# First_part depends if there is a number or not
try:
Multiplier = int(STR[Bound1_ID - 1])
First_part = STR[:Bound1_ID - 1]
except:
Multiplier = 1
First_part = STR[:Bound1_ID]
Middle_part = STR[Bound1_ID + 1: Bound2_ID] * Multiplier
# Assemble the new STR :
New_STR = First_part + Middle_part + Last_part
# Recursive command, repeat the function on the new STR
return Treatment(New_STR)
print (Treatment(Input))
EDIT : That's what it does :
First iteration : "2[ab[cd]]"
Second iteration : "2[abcd]"
Third iteration : abcdabcd => No more "[" so stop here.

Related

RLE ALgorithm in python

like the title suggest I want to do an RLE algorithm and I have few problems with that
for example in RLE algorithm if we take aaaabbbccd it should return a4b3c2d1 as a result
the rle function should return the compressed string of aaabbbccccddddd
rle(data : str) : str
so it would be a3b3c4d5
Here's the code I know it's wrong but I don't know If it was a good way to begin
def rle(data):
data = 'aaabbbccccddddd'
for i in range(0,len(data)):
if data.count(f'{i}') > 1:
data.replace(i, data.count(f'{i}'))
print(data)
print(rle(data))
data = 'aaabbbccccddddd'
seq = []
r = None
for d in data:
if d != r:
seq.append(d)
seq.append(str(1))
r = d
else:
seq[-1] = str(int(seq[-1]) + 1)
print("".join(seq))
I thought that this code snippet is simple, and so didn't explain it...
we have a str and want to convert it to Char-TheNumberOfRepetitions pairs, like ['a',3,'b',3,'c',4,...], so we loop a char over str and when it is new, we add [char, 1] to list, otherwise, we add 1 to last element of list while we get a new char...
r variable is for new char recognition and is a temp variable that we store every new char (if a char was not equal to it, replace)
finally, we convert ['a',3,'b',3,'c',4,...] to str, using join
why we use str() and int()? because python join method is a bit silly :) and throw an exception, if an element of list be int... and everytime we convert it to int to add 1 and then convert to str, again...
why not map? because I assume that OP is beginner and map is complicate for him...
and, a more pythonic way:
def rle(data: str) -> str:
seq = [data[0], 1]
for elem in data[1:]:
if elem != seq[-2]:
seq += [elem, 1]
else:
seq[-1] += 1
return ''.join(map(str, seq))
and reverse:
def reverse_rle(data: str, end_char = '$') -> str:
def convert(): return seq[:-2] + [seq[-2] * (seq[-1] or 1)]
seq = [data[0], 0]
for elem in data[1:] + end_char:
if elem.isdigit():
seq[-1] = seq[-1] * 10 + int(elem)
else:
seq = convert()
if elem != end_char:
seq += [elem, 0]
return "".join(seq)
and if you dont want to use end_char:
def reverse_rle(data: str) -> str:
def convert(): return seq[:-2] + [seq[-2] * (seq[-1] or 1)]
seq = [data[0], 0]
for elem in data[1:]:
if elem.isdigit():
seq[-1] = seq[-1] * 10 + int(elem)
else:
seq = convert() + [elem, 0]
return "".join(convert())
This should work better
def rle(data):
# Initialize a few variables
prev = None
cnt = 0
res = ""
for i in data:
if i == prev:
# if same char as previous one, just add one to counter
cnt += 1
else:
# Check that we are not at first round and add to result
if prev != None:
res += "%s%s" % (cnt,prev)
# Set new character as previous one
prev = i
# Add last char to result
res += "%s%s" % (cnt,prev)
return res
print(rle("aaabbbccccddddd"))

how to recursively remove all adjacent characters that have repeated 3 or more times using python

Test Cases
Input: abbbaaccada
Output: ccada
Input: bbccdddcb
Output: (Empty string)
str = input("Enter string: ")
def my_string(string):
if not string:
return ""
if len(string) == 1:
return string
if string[0] == string[1] == string[2]:
return my_string(string[3:])
return string[0] + my_string(string[1:])
print (my_string(str))
I am new to python. and I am trying to remove characters with 3 or more consecutive appearance in a string. In this I could only able to get output of only 1 iteration. e.g. i/p- hhhelllo o/p-eo but for i/p- abbbaaccada o/p is aaaccada but it should be ccada.. please help..
I have done this till 3 repetition but how to generalize it for more than 3 repetition.??
Your problem presents the opportunity to show how else in for loops can be useful. Take a look:
def remover(my_str):
temp = set(my_str)
while True:
for c in temp:
if 3*c in my_str:
my_str = my_str.replace(3*c, '')
break
else:
break
return my_str
test1 = 'abbbaaccada'
print(remover(test1)) # -> ccada
test2 = 'i/p- hhhelllo'
print(remover(test2)) # -> i/p- eo
If you insist on having recursive calls, you can modify the above as follows:
def remover(my_str):
temp = set(my_str)
new_str = my_str
for c in temp:
if 3*c in new_str:
new_str = new_str.replace(3*c, '')
if my_str == new_str:
return new_str
else:
return remover(new_str)
I have added a solution which will work for 3 or more repetition as the above solution didn't work for me. It is a recursive solution.
import re
def format_string(u_str):
f_str = remove_string(u_str)
if f_str == u_str:
return f_str
else:
return format_string(f_str)
def remove_string(u_str):
index = 0 # This will maintain the index while traversing the entire string
while index < len(u_str):
r = re.search(u_str[index]*4 + '*', u_str)
if r:
start, end = r.span() # start and end index of substring matching 3 or more repetition
u_str = u_str[:start] + u_str[end:] # removing the found substring
index = end
else:
index += 1
return u_str
test1 = 'abbbaaccada'
print('output:' + format_string(test1))
test2 = 'bbccdddcb'
print('output:' + format_string(test2))

How are finite automata implemented in code?

How does one implement a DFA or an NFA for that matter in Python code?
What are some good ways to do it in Python? Are they ever used in real world projects?
A straightforward way to represent a DFA is as a dictionary of dictionaries. For each state create a dictionary which is keyed by the letters of the alphabet and then a global dictionary which is keyed by the states. For example, the following DFA from the Wikipedia article on DFAs
can be represented by a dictionary like this:
dfa = {0:{'0':0, '1':1},
1:{'0':2, '1':0},
2:{'0':1, '1':2}}
To "run" a dfa against an input string drawn from the alphabet in question (after specifying the initial state and the set of accepting values) is straightforward:
def accepts(transitions,initial,accepting,s):
state = initial
for c in s:
state = transitions[state][c]
return state in accepting
You start in the initial state, step through the string character by character, and at each step simply look up the next state. When you are done stepping through the string you simply check if the final state is in the set of accepting states.
For example
>>> accepts(dfa,0,{0},'1011101')
True
>>> accepts(dfa,0,{0},'10111011')
False
For NFAs you could store sets of possible states rather than individual states in the transition dictionaries and use the random module to pick the next state from the set of possible states.
Here is my version of a dfa implementation if you're looking for a more object-oriented one. I was however ever so slightly inspired by John Coleman's answer.
class Node:
def __init__(self, val):
self.val = val
self.links = []
def add_link(self, link):
self.links.append(link)
def __str__(self):
node = "(%s):\n" % self.val
for link in self.links:
node += "\t" + link + "\n"
return node
def __add__(self, other):
return str(self) + other
def __radd__(self, other):
return other + str(self)
def equals(self, node):
ok = (self.val == node.val)
if len(self.links) == len(node.links):
for i in range(len(self.links)):
ok = ok and (self.links[i] == node.links[i])
return ok
else:
return False
class Link:
def __init__(self, from_node, etiquette, to_node):
self.from_node = from_node
self.etiquette = etiquette
self.to_node = to_node
def __str__(self):
return "(%s --%s--> %s)" % (self.from_node.val, self.etiquette, self.to_node.val)
def __add__(self, other):
return str(self) + other
def __radd__(self, other):
return other + str(self)
def equals(self, link):
return (self.from_node == link.from_node) and (self.etiquette == link.etiquette) and (self.to_node == link.to_node)
class Automata:
def __init__(self, initial_node, nodes, terminal_node):
self.initial_node = initial_node
self.nodes = nodes
self.terminal_node = terminal_node
def get_next_node(self, current_node, etiquette):
for link in current_node.links:
if link.etiquette == etiquette:
return link.to_node
return None
def accepts(self, string):
node = self.initial_node
for character in string:
node = self.get_next_node(node, character)
return self.terminal_node.equals(node)
def __str__(self):
automata = "Initial node: %s\nTerminal node: %s\n" % (self.initial_node.val, self.terminal_node.val)
for node in self.nodes:
automata += node
return automata
def __add__(self, other):
return str(self) + other
def __radd__(self, other):
return other + str(self)
if __name__ == '__main__':
pass
s0 = Node("s0")
s1 = Node("s1")
s2 = Node("s2")
s0_0_s0 = Link(s0, '0', s0)
s0_1_s1 = Link(s0, '1', s1)
s1_0_s2 = Link(s1, '0', s2)
s1_1_s0 = Link(s1, '1', s0)
s2_0_s1 = Link(s2, '0', s1)
s2_1_s2 = Link(s2, '1', s2)
s0.add_link(s0_0_s0)
s0.add_link(s0_1_s1)
s1.add_link(s1_0_s2)
s1.add_link(s1_1_s0)
s2.add_link(s2_0_s1)
s2.add_link(s2_1_s2)
a = Automata(s0, [s0, s1, s2], s0)
print(a)
print(a.accepts('1011101')) #True
print(a.accepts('10111011')) #False
Here I present a recursive solution for NFA. Consider the following nfa:
The transitions can be represented using list of lists as follows:
transition = [[[0,1],[0]], [[4],[2]], [[4],[3]], [[4],[4]],[[4],[4]]]
Note: State 4 is a hypothetical state. Once you go to that state, you can't move further. It is helpful when you can't read the input from the current state. You directly go to the state 4 and say input is not accepted for current progress(Check other possibilities by going back). e.g, if you are at q1, and the current input symbol is 'a', you go to state 4 and stop computing further.
Here is the Python code:
#nfa simulation for (a|b)*abb
#state 4 is a trap state
import sys
def main():
transition = [[[0,1],[0]], [[4],[2]], [[4],[3]], [[4],[4]]]
input = raw_input("enter the string: ")
input = list(input) #copy the input in list because python strings are immutable and thus can't be changed directly
for index in range(len(input)): #parse the string of a,b in 0,1 for simplicity
if input[index]=='a':
input[index]='0'
else:
input[index]='1'
final = "3" #set of final states = {3}
start = 0
i=0 #counter to remember the number of symbols read
trans(transition, input, final, start, i)
print "rejected"
def trans(transition, input, final, state, i):
for j in range (len(input)):
for each in transition[state][int(input[j])]: #check for each possibility
if each < 4: #move further only if you are at non-hypothetical state
state = each
if j == len(input)-1 and (str(state) in final): #last symbol is read and current state lies in the set of final states
print "accepted"
sys.exit()
trans(transition, input[i+1:], final, state, i) #input string for next transition is input[i+1:]
i = i+1 #increment the counter
main()
Sample Run(strings ending with abb are accepted):
enter the string: abb
accepted
enter the string: aaaabbbb
rejected
You don't need a for loop over range(len(input)) if you're using recursion. You're overcomplicating the code. Here's a simplified version
import sys
def main():
transition = [[[0,1],[0]], [[4],[2]], [[4],[3]], [[4],[4]]]
input = raw_input("enter the string: ")
input = list(input) #copy the input in list because python strings are immutable and thus can't be changed directly
for index in range(len(input)): #parse the string of a,b in 0,1 for simplicity
if input[index]=='a':
input[index]='0'
else:
input[index]='1'
final = "3" #set of final states = {3}
start = 0
trans(transition, input, final, start)
print "rejected"
def trans(transition, input, final, state):
for each in transition[state][int(input[0])]: #check for each possibility
if each < 4: #move further only if you are at non-hypothetical state
state = each
if len(input)==1:
if (str(state) in final): #last symbol is read and current state lies in the set of final states
print "accepted"
sys.exit()
else:
continue
trans(transition, input[1:], final, state) #input string for next transition is input[i+1:]
main()
I have implemented dfa which works for any of the dfa. But this is not in object oriented pattern.
states=list(map(int,input("Enter States : ").split(" ")))
symbols=list(input("Enter Symbols : ").split(" "))
initial_state=int(input("Enter initial state : "))
final_states=list(map(int,input("Enter final states : ").split(" ")))
transitions=[]
inlists=[]
for i in range(len(symbols)):
print("Enter transitions for symbol "+symbols[i]+" from all states :")
for j in range(len(states)):
inlists.append(int(input()))
transitions.append(inlists)
inlists=[]
cur_state=initial_state
while(1):
cur_state=initial_state
string=input("Enter string : ")
if string=='#':
break
for symbol in string:
print("["+str(cur_state)+"]"+"-"+symbol+"->",end="")
cur_state=transitions[symbols.index(symbol)][cur_state]
if cur_state in final_states:
print("["+str(cur_state)+"]")
print("String is accepted.")
else:
print("["+str(cur_state)+"]")
print("String is not accepted.")
Accepting string 101* and 001* modification of #John Coleman
#Dfa for accepting only 101+00101001
dfa101 = {0:{'1':1},
1:{'0':2},
2:{'1':3},
3:{'0':3, '1':3}}
#Dfa for accepting only 001+00101001
dfa001={0:{'0':1},
1:{'0':2},
2:{'1':3},
3:{'0':3, '1':3}}
def accepts(transitions,initial,accepting,s):
state = initial
try:
for c in s:
state = transitions[state][c]
if(state in accepting):
return 'Accepted'
else:
return 'Rejected'
except:
return 'Rejected'
print('Dfa of 101+ ',accepts(dfa101,0,{3},'10101111000')) #Accepted
print('Dfa of 001+ ',accepts(dfa001,0,{3},'00101010101')) #Accepted
To showcase my solution, let's take the following DFA as an example:
Language over 𝛴 = (0, 1) containing strings that are either made up of only 1’s or strings in which every 0 is followed by a 1.
The transition table for this DFA is:
delta
0
1
->*S
A
S
A
D
S
D
D
D
My program, written in Python3, is designed to accept the transition table of any DFA over the alphabet (0, 1) to check whether a string will be accepted by the DFA or not.
To use my program, we have to input the above transition table in the following format into a text file named fa.txt present in the same directory as the program.
fa.txt:
->*s(a,s)
a(d,s)
d(d,d)
For start state, the state name must be preceded by -> and a final state must be preceded by *. In case the start state is a final state, -> must come before *.
The state name must be only one character in length.
The start state must be named s.
The order of the states in the TXT file is irrelevant.
The code:
file = open("fa.txt", "r")
l = file.readlines()
x = 0
def findState(state):
lines = l
for i in range(0, len(lines)):
if lines[i][0] == '-':
lines[i] = lines[i][2::]
if lines[i][0] == '*':
if state == lines[i][1]:
return [lines[i][3], lines[i][5], 1]
if lines[i][0] == state:
return [lines[i][2], lines[i][4], 0] # state to go to on 0, state to go to on 1, is it final?
s = input("Enter a binary string to test it against the DFA in file fa.txt: ")
on0_on1 = findState('s') # start state
print("s", end = "")
for c in range(0, len(s)):
if s[c] != '0' and s[c] != '1':
print("Fail")
exit(0)
if s[c] == '0':
print(' ---0--->', on0_on1[0], end = '')
on0_on1 = findState(on0_on1[0])
else:
print(' ---1--->', on0_on1[1], end = '')
on0_on1 = findState(on0_on1[1])
if on0_on1[2] == 1 and c == len(s) - 1:
print("\nPass")
elif c == len(s) - 1 and on0_on1[2] == 0:
print("\nFail")

Returning multiple values in python, from csv

I'm working with a CSV-file, from which I might get multiple values. For example, a file with books, which might have multiple writers, for example {Ben Norrington|Chad Andersson}. They have together written a book.
In my code, I'm using regular expressions to split by the | and take remove the { and the }. It works fine.
The problem comes when I want to return the names of the writers. I only get the first name, not the second. How do I get both?
This is my code that takes a column from the CSV-file. The code is written in python 2.7
def ifseveral(x):
if "{" not in x and "(" not in x and x != "NULL":
return x
elif "{" in x:
splits =""
splits = x.split("|")
for i in splits:
string = i
string = re.sub('[{}]', '', string)
if "(" in string:
splitpar = ""
splited = string.split("(")
splitpar += splited[0][0:]
return splitpar
else:
**return string** #here is the problem
else:
return "No information available"
Return breaks the loop, therefore only the first split will be returned. You have to adjust your logic so that you add your splits to a datatstructure (or even a simple string) and return the entire structure after the for loop.
This could do the job though it's untested.
def ifseveral(x):
if "{" not in x and "(" not in x and x != "NULL":
return x
elif "{" in x:
splits =""
splits = x.split("|")
return_value = ""
for i in splits:
string = i
string = re.sub('[{}]', '', string)
if "(" in string:
splitpar = ""
splited = string.split("(")
splitpar += splited[0][0:]
return splitpar
else:
return_value += string+" "
return return_value
else:
return "No information available
A function can return only a single object. That object can be a simple object such as an integer, or a string, or it can be a more complex object such as a list of objects or it can be a generator.
The return statement returns from the function. The function does not (can not) continue executing.
Since you put a return statement in a for loop, when the return is reached the loop no longer continues to process additional data.
One solution: build a list and return it
def ifseveral(x):
# ...
result = []
for string in splits:
# ...
if "(" in string:
splitpar = ""
splited = string.split("(")
splitpar += splited[0][0:]
result.append(splitpar)
else:
result.append(string)
return result
foo = ifseveral("something")
print(foo)
print(len(foo))
for name in foo:
print("One of the names is", name)
Another solution is for your function to be a generator:
def ifseveral(x):
# ...
for string in splits:
# ...
if "(" in string:
splitpar = ""
splited = string.split("(")
splitpar += splited[0][0:]
yield splitpar
else:
yield string
return result
foo = ifseveral("something")
print(foo)
for name in foo:
print("One of the names is", name)

Pop from Empty list error

I am trying to push elements from a list to a stack. Here is the code:
#!/usr/bin/python
class Stack :
def __init__(self) :
self.items = []
def push(self, item) :
self.items.append(item)
def pop(self) :
return self.items.pop()
def isEmpty(self) :
if self.items == []:
return true
def InsertIntostacks(lst1):
X = Stack() #for each expression a stack is defined
Y = Stack()
for words in lst1:
if (ord(words) >= 48 and ord(words) <= 57) or (ord(words) >=65 and ord(words) <= 90):
X.push(words)
else:
Y.push(words)
print X.pop()
if __name__ == '__main__':
a = open("testinput1.txt","r+")
wordList = [line.strip() for line in a];
#print wordList[1]
lst=list()
for words in wordList:
if words == '#':
print "End of file"
else:
lst = list(words)
lst1 = list()
print lst
for x1 in lst:
if x1 != ' ':
lst1.append(x1)
InsertIntostacks(lst1)
So X is getting populated and I need Y to contain the operators, but apparently none of the elements are getting in Y ( input like A=B=C, so Y should contain = = ).
If i remove the constraints and just push all the elements in one stack the operators are there.
What am I doing wrong here?
I suspect maybe your indentation is wrong for InsertIntostacks(lst1), and that's the problem.
Try ensuring that InsertIntostacks(lst1) is properly aligned with the for loop, meaning it executes after the loop, not within it. Right now it's executing during every iteration of the loop, including the first one, where lst is indeed empty.

Categories

Resources