I have really been struggling to solve this problem. This is the problem:
Given a string describing the circuit, calculate the total resistance
of the circuit.
Here is an example:
input: 3 5 S
expected output: 8
The operands in the string are trailed by the operator, denoting if the resistors are either in Series or Parallel. However let's analyze a more complicated circuit:
input: 3 5 S 0 P 3 2 S P
expected output: 0
Step by step:
The 3 5 S at the beginning of the input gives us 8 and hence the first intermediate step is the string 8 0 P 3 2 S P.
8 0 P gives us 0, as one resistor is short-circuited and consequently we get 0 3 2 S P.
3 2 P is 5.
and finally 0 5 P is 0.
Here is my attempt. I tried using recursion as it seemed like a problem that can be solved that way. Firstly I wrote a helper function:
def new_resistance(a,b,c):
if c == '':
if int(a) == 0 or int(b) == 0:
return 0
else:
return 1/(1/int(a) + 1/int(b))
else:
return int(a) + int(b)
And the function that calculates the newn resistance of the circuit:
def resistance(array):
if isinstance(array, int):
return array
else:
if isinstance(array,list):
temp = array
else:
temp = array.split(" ")
i = 0
while True:
try:
a = new_resistance(temp[i], temp[i+1], temp[i+2])
except Exception as e:
i += 1
if len(temp[i+3:]) == 0:
return resistance(new_resistance(temp[i], temp[i+1], temp[i+2]))
else:
return resistance(temp[:i] + [new_resistance(temp[i], temp[i+1], temp[i+2])] + temp[i+3:])
The idea behind the program is to start at the beginning of the list and calculate the resistance of the first three elements of the list, then to append them at the beginning of a new list (without the three elements) and call the function again with the new list. Do this until only a single integer remains and return the integers.
Any help is appreciated.
UPDATE:
The solution to the problem, using a stack and a parser similar to a NPR parser.
operator_list = set('PS')
def resistance(circuit):
temp = circuit.split(" ")
stack = []
for char in temp:
if char in operator_list:
a = new_resistance(stack.pop(), stack.pop(), char)
print(a)
stack.append(a)
else:
print(char)
stack.append(char)
return stack[-1]
def new_resistance(a,b,c):
if c == 'P':
if float(a) == 0 or float(b) == 0:
return 0
else:
return 1/(1/float(a) + 1/float(b))
else:
return float(a) + float(b)
circuit = '3 5 S 0 P 3 2 S P'
resistance(circuit)
# 3
# 5
# 8.0
# 0
# 0
# 3
# 2
# 5.0
# 0
The problem is that once you reach 0 3 2 S P, you cannot simply take the first 3 elements. You need to look for number number S_or_P, wherever it is in the string.
You can use a regex for this task:
import re
circuit = '3 5 S 0 P 3 2 S P'
pattern = re.compile('(\d+) +(\d+) +([SP])')
def parallel_or_serie(m):
a, b, sp = m.groups()
if sp == 'S':
return str(int(a) + int(b))
else:
if a == '0' or b == '0':
return '0'
else:
return str(1/(1/int(a) + 1/int(b)))
while True:
print(circuit)
tmp = circuit
circuit = re.sub(pattern, parallel_or_serie, circuit, count=1)
if tmp == circuit:
break
# 3 5 S 0 P 3 2 S P
# 8 0 P 3 2 S P
# 0 3 2 S P
# 0 5 P
# 0
Note that 1 1 P will output 0.5. You could replace int by float and modify the regex in order to parse floats.
Your program, or more specifically your parser, seems to be relying on the Reverse Polish Notation, which in turn is a small variant of the Normal Polish Notation. Simply put, the RPN is an abstract representation where the operators of an arithmetical expression follow their operands, unlike in the Normal Polish Notation where the operators precede their operands. Parsers based on this representation can be easily implemented by using stacks (and usually do not need to interpret parentheses).
If you are tasked with developing that parser you may get some input from the Wikipedia article I linked above.
Credits to #none who first recognized the RPN.
Old memories came to my mind. I was playing with the FORTH language on 8-bit computers in 1980s. OK, back to Python:
circuit = '3 5 S 0 P 3 2 S P'
stack = []
for n in circuit.split():
if n == 'S':
r1 = stack.pop()
r2 = stack.pop()
stack.append(r1+r2)
elif n == 'P':
r1 = stack.pop()
r2 = stack.pop()
stack.append(0.0 if (r1 == 0 or r2 == 0) else 1/(1/r1+1/r2))
else:
stack.append(float(n))
assert len(stack) == 1
print(stack[0])
On in the spirit of VPfB for any combination of serial parallel (not only in pairs)
def calculateresistor(dataString):
stack = []
r = []
cicuit=dataString
for n in circuit.split():
if n == 'S':
stackSize=size(stack)
if size(stack)>=2:
for k in range(0,size(stack)-1):
r.append(float(stack.pop()))
r.append(float(stack.pop()))
stack.append((r[-1]+r[-2]))
elif n == 'P':
stackSize=size(stack)
if size(stack)>=2:
for k in range(0,size(stack)-1):
r.append(float(stack.pop()))
r.append(float(stack.pop()))
r.append(0.0 if (r[-1] == 0 or r[-2] == 0) else (1/(1/r[-1]+1/r[-2])))
stack.append(r[-1])
else:
stack.append(float(n))
assert len(stack) == 1
return(stack)
Related
I've managed to make the code work but i believe it could be optimized... a lot.
The input is a string of numbers separated with spaces. Something like - 4 2 8 6 or 1 2 3 4 5 6 7
It has to find which 3 numbers match this condition a + b == c. While 'b' is always on the right side of 'a' and for every time the condition is met print the numbers on the console in the following format - 'a + b == c'. If there isn't a single match print 'No'.
The only restriction is for 'b' to be at least 1 index away from 'a'.
This is what I have come up with.
lineOfNums = input('Line of numbers: ') # User input: example - 4 2 6 8
arrNums = lineOfNums.split()
conMet = False # Is the condition met at least once
for a in range(0, len(arrNums)):
for b in range(a + 1, len(arrNums)):
for c in range(0, len(arrNums)):
if int(arrNums[a]) + int(arrNums[b]) == int(arrNums[c]):
print(f'{arrNums[a]} + {arrNums[b]} == {arrNums[c]}')
conMet = True
if conMet == False: print('No')
You can do it with itertools, first of course convert to int
from itertools import combinations
# Convert to int
arr= [int(i) for i in arrNums]
# Get all the combinations
psums = {sum(i): i for i in combinations(arr, 2)}
# Then loop once
for i, v in enumerate(arr):
if v in psums:
print(f'{psums[v][0]} + {psums[v][1]} == {v}')
The big O for this algorithm is O(n^2) on average, which comes from O(n choose r), where n is the number of inputs (4 in this example) and r is the count of numbers your summing, in this case 2.
First, do the integer conversion once when you create arrNum, not every time through the loops.
arrNum = [int(x) for x in lineOfNums.split()]
The outer loop only needs to go to len(arrNums)-1, since it needs to leave room for B to the right of it.
for a in range(0, len(arrNums)-1):
for b in range(a + 1, len(arrNums)):
for c in range(0, len(arrNums)):
if arrNums[a] + arrNums[b] == arrNums[c]:
print(f'{arrNums[a]} + {arrNums[b]} == {arrNums[c]}')
conMet = True
Just I check if for example 1 + 2 is equal to 3 so it means 0011 in binary code.
ox_number = 361
output = []
for num in ox_number.split():
if 1 == num:
output.append("001")
elif 1 + 2 == num:
output.append("011")
else 1 + 2 + 4 == num:
output.append("111")
connected = ''.join(output)
rever_ = reversed(connected)
print(rever_)
You can convert your integer to and from an octal formatted string by using
your_int = 386
its_octal_is = f"{your_int:o}"
# Equivalent to
its_octal_is = "{:o}".format(your_int)
int_from_octal_string = int("386",8)
You might want to have a look at int documentation as well as the formatting expressions here.
I am trying to reformat somewhat inconsistent values (OCR) to a standard form based on a set of rules. These values come over typically as a fraction i.e. 4 3/4 but the values are sometimes polluted with other random characters i.e. 4 .3/4. The values can also be non fractional floats (4.75). The goal is to grab the values and produce the number; input = 'T 3/' output = 3. The values will never exceed 11.
I'm sure there's a better way to do this, but this is what I have so far, and it works on most but it doesn't catch everything. Any help to help handle exceptions like 'T 3/' would be appreciated.
a = ' Y 3/'
def get_num(t):
return str(''.join(ele for ele in t if ele.isdigit()))
t = get_num(a)
y = int(t)
z = a.split('.')[0]
print len(t)
if '/' in a:
if int(str(y)[:1]) == 1 and int(str(t)[1]) != 1 and len(t) == 4 and t <1199:
print '{}{} {}/{}'.format(*t)
if int(str(y)[:1]) == 1 and int(str(t)[1]) != 1 and len(t) == 4 and t >1199:
print '{} {}/{}'.format(*t[1:])
if int(str(y)[:1]) != 1 and int(str(t)[1]) != 1 and len(t) == 3:
print '{} {}/{}'.format(*t)
if int(str(y)[:1]) != 1 and int(str(t)[1]) == 1 and len(t) == 3:
print '{} {}/{}'.format(*t)
elif '.' in a and '/' not in a:
if int(z) == 1 and len(z) == 1:
print a.replace(' ','')
if int(z) > 11 and len(z) > 1 and int(t[:1]) == 1:
print a.replace(' ','')[1:]
if int(z) != 1 and len(z) <= 2:
print a.replace(' ','')
elif '.' not in a and '/' not in a:
if int(str(y)[:1]) == 1 and int(str(t)[1]) != 1 and len(t) == 4 and t <1199:
print '{}{} {}/{}'.format(*t)
if int(str(y)[:1]) == 1 and int(str(t)[1]) != 1 and len(t) == 4 and t >1199:
print '{} {}/{}'.format(*t[1:])
if int(str(y)[:1]) != 1 and int(str(t)[1]) != 1 and len(t) == 3:
print '{} {}/{}'.format(*t)
if int(str(y)[:1]) != 1 and int(str(t)[1]) == 1 and len(t) == 3:
print '{} {}/{}'.format(*t)
else:
print(a)
Common Sample Inputs/Outputs (many more combos):
In: 4 3/4 | Out: 4 3/4
In: 4.75 | Out: 4.75
In: T 3/ | Out: 3
In: 14 3/4 | Out: 4 3/4 (leading 1 does not belong >11
In: 4 .33 | Out: 4.33
In: 3 2./3 | Out: 3 2/3
In: 3 ..33 | Out: 3.33
Essentially its a fraction if there is a '/' in the string even if it contains a '.'. If its not in the string, it's a decimal. If neither, then there is an opportunity there as well for some logic
Alright #FanScience, got an answer here. It works with all the inputs you gave, but it's slightly brittle -- happy to try to expand if you find there are inputs that it doesn't get along with.
First I imported two helpful libraries:
import re
from fractions import Fraction
Next I defined a dictionary with your inputs + expected outputs, so I could write a function that tested my methodology:
expected_results = {
"4 3/4": 4.75,
"4.75": 4.75,
"T 3/": 3,
"14 3/4": 4.75,
"4 .33": 4.33,
"3 2./3": 3.67,
"3 ..33": 3.33,
}
Next I got to writing the actual function -- let me know if you have any questions, as this is somewhat complex:
def generate_correct_float(to_convert):
# Removes any alphabetical character (A, B, a, b...)
to_convert = re.sub("[a-zA-Z]", "", elem)
# Removes extra whitespace on either end
to_convert = to_convert.strip()
final_answer = 0
if " " in to_convert: #two-part, ie 4 3/4
primary_number, secondary_number = to_convert.split()
final_answer += int(primary_number)
if "/" in secondary_number: # Fraction case
secondary_number = secondary_number.replace(".", "")
secondary_number = secondary_number.strip("/")
secondary_number = Fraction(secondary_number)
else: #Decimal Case
secondary_number = Fraction(int(secondary_number.replace(".", "")), 100)
final_answer += round(secondary_number.__float__(), 2)
else: # Single element, ie 3/
final_answer = to_convert.strip("/")
final_answer = float(final_answer)
# Eliminate cases where we're higher than 11
while final_answer > 11:
final_answer -= 10
return final_answer
Finally I wrote a wrapper function that tests inputs vs outputs and gives us a correct vs incorrect count:
incorrect = 0
for elem in expected_results:
answer = generate_correct_float(elem)
if answer != expected_results[elem]:
print('------')
print(elem)
print(expected_results[elem])
print(answer)
incorrect += 1
correct = len(expected_results) - incorrect
print(f"correct: {correct}")
print(f"incorrect: {incorrect}")
Running this with our code gives us 7/7, all with floats!
Hopefully this helps -- let me know if there are any points of clarification I can make #FanScience
I want to write a function "longest" where my input doc test looks like this (python)
"""
>>>longest('1211')
1
>>>longest('1212')
2
>>>longest('212111212112112121222222212212112121')
2
>>>lvs('1')
0
>>>lvs('121')
0
>>>lvs('12112')
0
"""
What I am trying to achieve is that for example in the first case the 1 is repeated in the back with "11" so the repeated part is 1 and this repeated part is 1 character long it is this length that this function should return.
So in the case of the second you got "1212" so the repeated part is "12" which is 2 characters long.
The tricky thing here is that the longest is "2222222" but this doesn't matter since it is not in the front nor the back. The solution for the last doc test is that 21 is being repeated which is 2 characters long.
The code I have created this far is following
import re
def repetitions(s):
r = re.compile(r"(.+?)\1+")
for match in r.finditer(s):
yield (match.group(1), len(match.group(0)) / len(match.group(1)))
def longest(s):
"""
>>> longest('1211')
1
"""
nummer_hoeveel_keer = dict(repetitions(s)) #gives a dictionary with as key the number (for doctest 1 this be 1) and as value the length of the key
if nummer_hoeveel_keer == {}: #if there are no repetitive nothing should be returnd
return 0
sleutels = nummer_hoeveel_keer.keys() #here i collect the keys to see which has has the longest length
lengtes = {}
for sleutel in sleutels:
lengte = len(sleutel)
lengtes[lengte] = sleutel
while lengtes != {}: #as long there isn't a match and the list isn't empty i keep looking for the longest repetitive which is or in the beginning or in the back
maximum_lengte = max(lengtes.keys())
lengte_sleutel = {v: k for k, v in lengtes.items()}
x= int(nummer_hoeveel_keer[(lengtes[maximum_lengte])])
achter = s[len(s) - maximum_lengte*x:]
voor = s[:maximum_lengte*x]
combinatie = lengtes[maximum_lengte]*x
if achter == combinatie or voor == combinatie:
return maximum_lengte
del lengtes[str(maximum_lengte)]
return 0
when following doc test is put in this code
"""
longest('12112')
0
""
there is a key error where I put "del lengtes[str(maximum_lengte)]"
after a suggestion of #theausome I used his code as a base to work further with (see answer): this makes my code right now look like this:
def longest(s):
if len(s) == 1:
return 0
longest_patt = []
k = s[-1]
longest_patt.append(k)
for c in s[-2::-1]:
if c != k:
longest_patt.append(c)
else:
break
rev_l = list(reversed(longest_patt))
character = ''.join(rev_l)
length = len(rev_l)
s = s.replace(' ','')[:-length]
if s[-length:] == character:
return len(longest_patt)
else:
return 0
l = longest(s)
print l
Still there are some doc tests that are troubling me like for example:
>>>longest('211211222212121111111')
3 #I get 1
>>>longest('2111222122222221211221222112211')
4 #I get 1
>>>longest('122211222221221112111')
4 #I get 1
>>>longest('121212222112222112')
6 #I get 1
Anyone has ideas how to deal with/ approach this problem, maybe find a more graceful way around the problem ?
Try the below code. It works perfectly for your input doc tests.
def longest(s):
if len(s) == 1:
return 0
longest_patt = []
k = s[-1]
longest_patt.append(k)
for c in s[-2::-1]:
if c != k:
longest_patt.append(c)
else:
break
rev_l = list(reversed(longest_patt))
character = ''.join(rev_l)
length = len(rev_l)
s = s.replace(' ','')[:-length]
if s[-length:] == character:
return len(longest_patt)
else:
return 0
l = longest(s)
print l
Output:
longest('1211')
1
longest('1212')
2
longest('212111212112112121222222212212112121')
2
longest('1')
0
longest('121')
0
longest('12112')
0
Here is the code:
aWord = input("enter the word now")
num = 0
def palindromeMethod(theWord):
length = len(theWord)
if(theWord[num]==theWord[length-num]):
if(num>length):
print("its a palindrome")
num = num+1
palindromeMethod(theWord)
else:
return False
palindromeMethod(aWord)
I am getting errors at the three nums, which say: unresolved reference 'num', and I am getting the error local variable 'num' referenced before assignment when I run it. But I defined num before the method, so why am I getting these errors? thanks
edit: answered it myself
In python, to keep track of variables that need to exist during the recursion, you use an argument with a default value.
def palindromeMethod(theWord, num=0):
# here ^
length = len(theWord)
if(theWord[num]==theWord[length-num-1]):
if(num>=length-1):
return True
return palindromeMethod(theWord, num+1)
# pass it here ^
else:
return False
if palindromeMethod('aabbccbbaa'):
# don't need to pass it here ^
print('its a palindrome')
I moved the print outside the function and fixed some off-by-one errors.
Variables inside the functions has a local scope ,thus you need to initial the num inside the function ! But as you have a recursion function here you couldn't specify a num=0 in your function .
So my suggestion for such problem is :
pass the num as an argument to your function :
def palindromeMethod(theWord,num=0):
length = len(theWord)
if(theWord[num]==theWord[length-num]):
if(num>length):
print(theWord, "is a palindrome")
return True
num = num+1
return palindromeMethod(theWord,num)
else:
return False
No need for indices or lengths
def pal(w):
if w == "": return True
if w[0] != w[-1]: return False
return pal(w[1:-1])
but you may have been requested to use them...
Edit
Following a comment of the OP, that effectively narrows the spectrum of possible responses, here it is a look ma, no slices version of the above.
def pal(w, l=0, n=0):
# in production use: l = l if l else len(w)
if l ==0:
l = len(w)
print(("0123456789"*3)[:l])
print(w)
print(n, l-n-1, w[n], w[l-n-1])
if w[n] != w[l-n-1]: return False
if n+1 >= l-n-2: return True
return pal(w,l,n+1)
# a bit of testing
for word in ('aabbcbbaa', 'aabbccbbaa', 'aabbccbaa', 'aabbcdbbaa',
'saippuakivikauppias'):
print('Is the word "%s" palindrome? %s.' % (word, pal(word)))
The print expressions were used to show the work in progress of the function, the OP may want to remove them, as they were not requested (NB: w/o prints etc it's 5 LOC).
Output of testing
012345678
aabbcbbaa
0 8 a a
1 7 a a
2 6 b b
3 5 b b
Is the word "aabbcbbaa" palindrome? True.
0123456789
aabbccbbaa
0 9 a a
1 8 a a
2 7 b b
3 6 b b
4 5 c c
Is the word "aabbccbbaa" palindrome? True.
012345678
aabbccbaa
0 8 a a
1 7 a a
2 6 b b
3 5 b c
Is the word "aabbccbaa" palindrome? False.
0123456789
aabbcdbbaa
0 9 a a
1 8 a a
2 7 b b
3 6 b b
4 5 c d
Is the word "aabbcdbbaa" palindrome? False.
0123456789012345678
saippuakivikauppias
0 18 s s
1 17 a a
2 16 i i
3 15 p p
4 14 p p
5 13 u u
6 12 a a
7 11 k k
8 10 i i
Is the word "saippuakivikauppias" palindrome? True.
Final fireworks: the much expected one-liner
def pal(w): return 1 if w=="" else 0 if w[0]!=w[-1] else pal(w[1:-1])
ok I played around with it and came up with this, which works with no errors:
aWord = input("enter the word now")
num = 0
def palindromeMethod(theWord, num):
length = len(theWord)
if(theWord[num]==theWord[length-(1+num)]):
if(num>=length-1):
print("its a palindrome")
return True
num = num+1
palindromeMethod(theWord,num)
else:
return False
palindromeMethod(aWord,0)
however i am not 100% certain why this works. I'm guessing that when i say 'return True' it breaks out of the outer if block and doesn't execute the next two lines in the if block (num = num+1 and palindromeMethod(theWord,num).... is this correct?