I have a function, which checks given two node chains and determines whether those two node chains contain same data values in same order. Function returns True if they do and returns False otherwise. I need to write this function using recursion.
Here's my attempt:
def check_chains(chain1, chain2):
if chain1 is None or chain2 is None:
return False
else:
if chain1.get_data() == chain2.get_data():
check_chains(chain1.get_next(), chain2.get_next())
return True
else:
return False
This one returns True even if node chains have different data values in them.
Below are some test cases:
1. Test case 1 (test passed)
chain1 = N.node(5 ,N.node(10,N.node(-15, N.node(1))))
chain2 = N.node(5 ,N.node(10,N.node(-15, N.node(1))))
expected = True
result = a7q8.check_chains(chain1, chain2)
if result!=expected:
print('Test failed')
2. test 2 (test failed, expected false but returned True)
chain1 = N.node(5 ,N.node(10,N.node(-15, N.node(1))))
chain2 = N.node(5 ,N.node(10,N.node(7, N.node(1))))
expected = True
result = a7q8.check_chains(chain1, chain2)
if result!=expected:
print('Test failed')
Your logic was a little bit flawed in two places:
def check_chains(chain1, chain2):
# base case for equality was missing!
if chain1 is chain2 is None:
return True
if None in (chain1, chain2): # rewrote your condition less verbosely
return False
if chain1.get_data() == chain2.get_data():
# recursive result was never used!
return check_chains(chain1.get_next(), chain2.get_next())
return False
I also removed some spurious else, as you return from every if-block.
def check_chains(chain1, chain2):
if chain1 is None and chain2 is None:
return True
if chain1 is None or chain2 is None:
return False
else:
if chain1.get_data() == chain2.get_data():
return check_chains(chain1.get_next(), chain2.get_next())
else:
return False
Related
1st if check is to ensure left i.e starting node and right i.e ending node data if they do not match false is returned, but control flow is not returned out of function, instead it keeps matching for other nodes and runs else condition for other cases.
class Node:
def __init__(self,data):
self.data = data
self.next = None
class LinkedList:
def __init__(self):
self.head = None
self.size = 0
self.tail = None
self.left = None
def palindromeHelper(self,right):
if(right == None):
return True
rres = self.palindromeHelper(right.next)
print(self.left.data, right.data)
if self.left.data != right.data:
return False
else:
self.left = self.left.next
return True
def isLinkedListPaliendrome(self):
right = self.left = self.head
print(self.palindromeHelper(right))
list4 = LinkedList()
list4.addLast('b')
list4.addLast('a')
list4.addLast('c')
list4.addLast('a')
list4.addLast('b')
list4.addLast('a')
list4.isLinkedListPaliendrome()
Output:
b a
b b
a a
c c
a a
b b
True
Your overall strategy makes sense:
Set a pointer to the front of the list.
Recursively get to the end of the list.
As the call stack unwinds (essentially moving backward through the list), move the pointer you set at the first step forward, comparing the data.
The trouble is you're ignoring intermediate False results. Consider this input:
abc
Note that no letter occurs twice. Let's see what happens:
left=a, right=a
left=a, right=b
left=a, right=c
left=a, right=null, return True
Now the stack starts to unwind. Left=a, right=c, return False
left=a, right=b, return False
left=a, right=a, move left to left.next (left=b), return True
Any string with a unique starting letter will return True because of this. In fact, many types of string will will return True, because the algorithm only considers the final comparison, ignoring intermediate failures.
What you need to do is use the intermediate result rres. If any step returns False, the whole call stack needs to return False as well.
I have a class for a Dialogue system as follows
class DIALOGUE(object):
def __init__(self, place, who, sTime, eTime, isActive, mood, menuText, func, repeatable, num):
self.place = place
self.who = who
self.sTime = sTime
self.eTime = eTime
self.isActive = isActive
self.mood = mood
self.menuText = menuText
self.func = func
self.repeatable = repeatable
self.num = num
#property
def ACheck(self):
global Date
if self.sTime == "none":
return True
else:
tHour,tMin = self.sTime.split(":")
if tHour >= Date.Hour and tMin <= Date.Minute:
tHour,tMin = self.eTime.split(":")
if tHour < Date.Hour and tMin < Date.Minute:
return True
return False
#property
def BCheck(self):
global Act
if self.who == Act:
return True
else:
return False
#property
def CCheck(self):
global Location
if self.place == Location:
return True
if self.place == "none":
return True
return False
#property
def DCheck(self):
if self.repeatable:
return True
else:
if self.num > 0:
return False
else:
return True
#property
def CanChat(self):
if self.isActive and self.ACheck and self.BCheck and self.CCheck and self.DCheck:
return True
else:
return False
def SetActive(self):
self.isActive = True
def Do(self):
self.num += 1
renpy.call(self.func)
Most of this should be self explanatory but I parse an XML file into a list of Instances of this class.
The user is presented with a list of available dialogues based on what Location they are in, what time of day it is and what NPC they have selected. If the dialogue is not repeatable The DCheck method looks at whether or not the dialogue has been completed before i.e if the dialogue is not repeatable and self.num > 0 the method will return False
Essentially it loops through all the dialogues and carries out i.CanChat and if this value returns True, the Dialogue is added to the menu
The issue I'm having is that the Check methods aren't returning the correct value. Specifically DCheck is returning True all the time, regardless of whether the Dialogue is repeatable or not, and ignoring the value of self.num
The class is created in an init python: block and then the xml file is parsed in a separate python block which is called from inside the start label
It's probably something really simple but I can't figure it out.
The list of instances is parsed as follows
Dialogues = []
for j in Dialo:
JPlace = j.find('Place').text
JWho = j.find('Who').text
JsTime = j.find('Start').text
JeTime = j.find('End').text
JMood = int(j.find('Mood').text)
JText = j.find('Text').text
JFunc = j.find('Func').text
JRep = j.find('Rep').text
if JRep == "True":
Jrep = True
else:
Jrep = False
Dialogues.append(DIALOGUE(JPlace, JWho, JsTime, JeTime, False, JMood, JText, JFunc, JRep, 0))
The method for creating the menu is as follows
def TalkCheck():
talks = []
talks.append(("Nevermind.", "none"))
for i, q in enumerate(Dialogues):
if q.CanChat:
talks.append((q.menuText,i))
renpy.say(None, "", interact=False)
talkchoice = renpy.display_menu(talks)
if talkchoice <> "none":
talkchoice = int(talkchoice)
Dialogues[talkchoice].Do()
Your question is incomplete - you didn't post a MCVE, we don't know the effective values for "repeatble" and "num" that leads to this behaviour, and we don't even know if it's using Python 2.x or Python 3.x - so we can just try and guess. Now since you mention that you "parse an XML file into a list of instances", I stronly suspect you are running Python 2.x and passing those values as strings instead of (resp.) boolean and int. In Python 2, "-1" (string) compares greater than 0 (int) - it raises a TypeError in Python 3.x -, and in both cases a non-empty string evals to True in a boolean context (bool('False') == True). Since there's no obvious logical error in your method implementation, that's the only explanation I can think of.
BTW, expressions have a boolean values and return exits the function, so you can simplify your code:
#property
def DCheck(self):
if self.repeatable:
return True
return self.num > 0
I have implemented the above implication in Python but it does not return the expected results:
True True None
True False None
False True True
False False None
My python code is:
def implies(a,b):
if a:
return b
else:True
return
for p in (True, False):
for q in (True, False):
print("%10s %10s %s" %(p,q,implies((p or q) and (not p), q)))
I don't understand the contradiction here. None implies False doesn't it? And why not print True like it should?
def implies(a,b):
if a:
return b
else:True
return
Your error is in the last two lines, if !a, you aren't returning a specific value, so the result is None.
You want:
def implies(a,b):
if a:
return b
else:
return True
I have two functions that contain mostly the same code. One returns "True" if the array passed in contains all positive numbers while the other returns "True" if the array contains all numbers that are divisible by 10.
I want to combine these two functions into a function like this:
def master_function(array, function):
for i in array:
if function:
result = True
else:
result = False
break
print(result)
return result
The only part that would vary is the "function" in the If statement. When I write functions with the missing line they don't get called as the program executes.
def positive_integers(array):
i >= 0
def divisible_by_10(array):
i%10 == 0
The test code isn't executed either.
master_function([10,20,30,35],divisible_by_10)
Your functions aren't returning anything, and you need to give them access to i:
def positive_integers(i):
return i >= 0
def divisible_by_10(i):
return not i%10
def master_function(array, function):
for i in array:
if function(i):
result = True
else:
result = False
break
print(result)
return result
Your function don't return anything. Also, you need read about all and any:
def positive_integers(array):
return all(i >= 0 for i in array)
def divisible_by_10(array):
return all(i % 10 == 0 for i in array)
def master_function(array, function):
return function(array)
def master_function(array, function):
for i in array:
print str(i)
if function(i):
result = True
else:
result = False
print(result)
return result
def positive_integers(i):
if i >= 0:
return True
def divisible_by_10(i):
if i%10 == 0:
return True
master_function([10,20,30,35],divisible_by_10)
I have a generator function that tracks whether I am between a certain pair of events-- a "start" event and an "end" event. For example, it could be examining tokens and reporting whether I am between the comment delimiters "/*" and "*/" (non-nesting). The following code works, but is there a nice itertools combination or logical restructuring that would simplify it (and/or make it more "pythonic")?
def tokspan(starttok, endtok, stream):
inside = False
for tok in stream:
if (not inside) and tok == starttok:
inside = True
yield (inside, tok)
if inside and tok == endtok:
inside = False
tstream = "int x; /* a non-nesting comment /* etc. */ x=1; main();".split()
for status, tok in tokspan("/*", "*/", tstream):
print(status, tok)
The above (intentionally) returns True for the boundary tokens (/* and */), but that's not particularly important. If you have an approach that happens to exclude one or both boundaries (like python ranges do), I'd still like to know about it.
The only simplification that I can think of is rewriting the logic around setting/resetting inside:
def tokspan(starttok, endtok, stream):
inside = False
for tok in stream:
inside |= (tok == starttok)
yield (inside, tok)
inside &= (tok != endtok)
Whether this makes the code more or less readable is in the eye of the beholder.
It might be possible to use a decorator over here. I am not sure if this is going to be useful to you or not but this might just give you some ideas.
Create a decorator which stores the items you want to filter out with:
import itertools as it
class insideDec(object):
def __init__(self, start, stop):
self.start = start
self.stop = stop
def __call__(self, f):
def wrapper(x):
x1 = it.dropwhile(lambda m: not m.startswith(self.start), x )
x1.next()
x2 = it.takewhile(lambda m: not m.startswith(self.stop), x1 )
return f(x2)
return wrapper
#insideDec('{', '}')
def f(val):
return val
if __name__ == '__main__':
print ''.join(f('This is some {string that needs to} be printed'))
Now you apply the decorator to a function that accepts a string. This will convert the function into one whose input is an iterator. You then process the iterator like you would any other iterator.
Of course, you can always convert the iterator to a string at any point of time (like for example over here):
# rest of the code ...
x2 = it.takewhile(lambda m: not m.startswith(self.stop), x1 )
return f(''.join(x2))
# rest of the code ...
That's really up to you ...
Edit:
Sorry about that. I misread your question. For tokenizing, maybe something like the following might help?
class tokenize():
def __init__(self, strVal, start, stop):
self.start = start
self.stop = stop
self.strTees = it.tee(strVal, len(start))
self.inside = False
for i, strTee in enumerate(self.strTees):
for j in range(i):
next(strTee, '')
self.strVals = it.izip( *self.strTees )
def __iter__(self):
return self
def next(self):
v = ''.join(self.strVals.next())
if v == '': raise StopIteration
if v == self.start: self.inside = True
if v == self.stop: self.inside = False
# print '[',v, ']'
return (v[0], self.inside)
if __name__ == '__main__':
strVal = 'int x; /* a non-nesting comment etc. */ x=1; main();'
for x, y in tokenize( strVal, '/*', '*/' ):
print x, y
Again, this is not perfect, by might serve your purposes ...
Here is the output:
i False
n False
t False
False
x False
; False
False
/ True
* True
True
a True
True
n True
o True
n True
- True
n True
e True
s True
t True
i True
n True
g True
True
c True
o True
m True
m True
e True
n True
t True
True
e True
t True
c True
. True
True
* False
/ False
False
x False
= False
1 False
; False
False
m False
a False
i False
n False
( False
) False